Card 04/ 07
Self-Invocation: Calling a @Transactional Method From the Same Class
A call through this never reaches the proxy, so the method runs with no transaction at all.
@Transactional only applies to calls that come through the bean's proxy, the wrapper object Spring puts in front of the bean to open and close the transaction. A method that calls another method of the same object, which is called self-invocation, makes an ordinary Java call on the real object, and the annotation on the called method does nothing.
publicMethod() calls this.transactionalMethod(), and transactionalMethod is annotated @Transactional. No transaction is active inside it anyway:
@Service
class SelfInvokeService {
void publicMethod() {
this.transactionalMethod();
}
@Transactional
void transactionalMethod() {
// runs with no transaction, when called from publicMethod()
}
}before internal call, transaction active = false
inside transactionalMethod, transaction active = false
called directly from outside the bean, transaction active = trueThe proxy wraps the bean, not each method. A call from another bean passes through the proxy and gets a transaction, which the third line confirms. this.transactionalMethod() is made from inside the real object, so it never goes through the proxy and none of its behaviour applies.
Nothing warns you: the code compiles, runs and passes simple tests, and the missing transaction only shows when a failure leaves half the writes in place.
The usual fix is to move transactionalMethod into a separate bean and inject it, so every call has to go through a proxy to reach it. Putting @Transactional on publicMethod instead also works, when the whole outer method should be one transaction.
← → move through sections and cards