Mastering Spring @Transactional: Propagation, Rollback, and Proxy Pitfalls

This article explains Spring's @Transactional annotation, detailing propagation behaviors, rollback rules, common pitfalls such as self-invocation and non‑public methods, and provides practical solutions using AOP proxies and AopContext to ensure proper transaction management in Java backend applications.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Mastering Spring @Transactional: Propagation, Rollback, and Proxy Pitfalls

Introduction

When dealing with complex business logic, controlling transactions with @Transactional becomes essential. This article shares insights gained from testing and debugging Spring transaction management.

Transaction Propagation Behaviors

Spring defines several propagation constants in TransactionDefinition: PROPAGATION_REQUIRED: Join the existing transaction or create a new one (default). PROPAGATION_REQUIRES_NEW: Always start a new transaction, suspending any existing one. PROPAGATION_SUPPORTS: Join an existing transaction if present; otherwise execute non‑transactionally. PROPAGATION_NOT_SUPPORTED: Execute non‑transactionally, suspending any existing transaction. PROPAGATION_NEVER: Execute non‑transactionally and throw an exception if a transaction exists. PROPAGATION_MANDATORY: Join an existing transaction or throw an exception if none exists. PROPAGATION_NESTED: Execute within a nested transaction if a transaction exists; otherwise behaves like PROPAGATION_REQUIRED.

Rollback Mechanism

Spring’s declarative transaction management rolls back on unchecked (runtime) exceptions. The transaction boundary starts before the business method and commits or rolls back after the method finishes, depending on whether a RuntimeException was thrown.

If a try{}catch(Exception e){} block swallows the exception, the transaction will not roll back unless you re‑throw a RuntimeException inside the catch block. This scenario is a common interview question.

Self‑Invocation Pitfall

When a method annotated with @Transactional calls another method of the same class via this.method2(), the second method’s annotation is ignored because the call bypasses the proxy that applies the transaction advice.

Additionally, the annotated method must be public. Non‑public methods are ignored by the proxy, though no error is reported.

Solution Using AOP Proxy

To invoke another method within the same class and still have transaction semantics, obtain the current proxy via AopContext.currentProxy() and call the method on that proxy. Enable proxy exposure with: @EnableAspectJAutoProxy(exposeProxy = true) Both methods must be public for the proxy to work.

Code Example

Controller calling the service:

@RestController
public class TransactionalController {
    @Autowired
    private TransactionalService transactionalService;

    @PostMapping("transactionalTest")
    public void transacionalTest() {
        transactionalService.transactionalMethod();
    }
}

Service interface:

public interface TransactionalService {
    void transactionalMethod();
}

Service implementation (illustrated with diagrams in the original article):

When both methods are called via the proxy, each can run in its own transaction (e.g., using PROPAGATION_REQUIRES_NEW) or share the same transaction, depending on the propagation setting.

Key Takeaways

@Transactional

ensures each method runs within a transaction; to trigger rollback, re‑throw a runtime exception inside a catch block.

Methods must be public for the annotation to take effect.

Self‑invocation bypasses the proxy; use AopContext.currentProxy() or restructure the code to avoid this issue.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaProxyaopdatabasespringtransactional
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.