Declarative Spring transaction advice applies at an intercepted method boundary; adding a transaction annotation does not make every target-to-target call enter that boundary.
Spring transactional methods: call paths and rollback assumptions
This lesson uses the downloadable source kit: Java 21, Spring Boot 4.0.8 and its managed Spring Framework 7 dependencies. The version is pinned for repeatable builds.
Inspect the actual call path
CounterTarget.outer calls inner directly, and the advice counter records only outer entering the proxy. This is the dispatch trap behind many self-invoked transactional methods. An annotation on inner is not evidence that the call went through transaction advice.
The kit deliberately pairs that proxy check with separate TransactionTemplate database rollback tests. It does not pretend that the counter fixture is an annotated service with a real transaction manager. Keeping the evidence separate prevents an interception demo from becoming a false database guarantee.
State the failure policy
Declarative rollback rules can distinguish unchecked and checked exceptions, and a swallowed exception can change what advice observes. Specify the intended rollback rule and test committed state for the failures your service actually throws.
If several operations must succeed together, choose one clear outer transaction owner. Starting a new transaction on another thread changes the connection and context boundary; async execution is not a transparent continuation of the caller’s transaction.
Checked source
Counter proxy = (Counter) factory.getProxy();
proxy.outer(); // outer is advised; inner is called directly by the target.
// The JDBC fixture tests rollback separately through TransactionTemplate.
ledger.batchThatFails();Test the boundary
Run mvn test in the source-kit directory. CoreBoundaryTest.selfInvocationBypassesProxyAdvice and ReceiptBoundaryTest.databaseFailureRollsBackWholeBatch checks the behavior described here. Java excerpts belong to the named source-kit classes; they are not independent source files unless the complete class is shown.
Costs and boundaries
Proxy advice and database transactions add different costs. This lesson establishes call-path and rollback boundaries separately; annotated propagation modes such as REQUIRES_NEW require dedicated database fixtures beyond this kit.
Common Mistakes
- Do not rely on self-invocation to start intercepted transactions.
- Do not swallow a failure without deciding the transaction outcome.
- Do not assume a transaction travels into an executor task.
Read next
Spring AOP proxies: self-invocation bypasses proxy advice, Spring TransactionTemplate: roll back a failed multi-row change, Java JDBC transactions: atomic updates and rollback.
Continue with ownership and failure checks
Continue with Spring transaction rollback: checked failures commit unless a rule says otherwise.
