Card 04/ 07

GotchaDifficulty: Advanced1 min

Calling Yourself Skips the Proxy

publicMethod() calls this.transactionalMethod(), and transactionalMethod is annotated @Transactional. No transaction is active inside it anyway.

java
@Service
class SelfInvokeService {

    void publicMethod() {
        this.transactionalMethod();
    }

    @Transactional
    void transactionalMethod() {
        // runs with no transaction, when called from publicMethod()
    }
}
text
before internal call, transaction active = false
inside transactionalMethod, transaction active = false
called directly from outside the bean, transaction active = true
run in a container, checked with TransactionSynchronizationManager.isActualTransactionActive()

@Transactional works through a proxy that wraps the bean, not the method. this.transactionalMethod() is a plain Java call on the real object, made from inside it — it never goes through the proxy at all, so none of the proxy's behaviour applies. Calling the exact same method from a different bean does go through the proxy, and does open a transaction, which the third line above confirms.

The fix, when this matters: move transactionalMethod to a separate bean and inject it, so every call — internal or not — has to go through the proxy to reach it.