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.
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
@Transactionalensures 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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
