Why might @Transactional NOT work in this code?
@Service
public class ReportService {
public void generate() {
saveAll(); // call inside the same class
}
@Transactional
public void saveAll() { ... }
}Options
- Because the method is public and it must be private
- Transactions use a proxy; a call within the class skips it (Correct option)
- Because
@Transactionalonly ever works on interfaces - Because the method has no parameters declared in it
Answer
Because Spring applies transactions through a proxy, and a call from another method of the same class (self-invocation) bypasses the proxy
Why
Spring does not change your class. It wraps the bean in a proxy object that starts and commits the transaction around the call.
When an outside class calls reportService.saveAll(), it goes through the proxy and works. But when generate() calls saveAll() inside the same object, it is a normal Java call on this, so the proxy is skipped and there is no transaction.
Same problem with private or final methods. Fix: move the method to another bean, or put @Transactional on the method called from outside.
Remember
Self-invocation and private methods bypass Spring's proxy.