Spring @Transactional method call by the method within the same class, does not work?
To make @Transactional
operations work when called from within the same class, you need to access via a proxy, preferably through self-injection:
This technique gives you the proxy instance and ensures that transactional support applies to internal method calls.
Why self-injection is necessary
Spring uses AOP proxies for transaction management. When you call a @Transactional
method, Spring checks if it's a proxy call. If you call the method directly (this.doTransactionalStuff()
), it bypasses the proxy, and hence Spring's transaction management.
To handle this, use self-injection: the class injects an instance of itself. Another approach involves initializing a proxy in a @PostConstruct
method to confirm transaction management applies for internal calls:
Alternatively, refactor your code: move transactional methods to a different class or interface. In other words, create a wingman for your transaction management:
Deeper transaction control with AspectJ
For transaction management at a granular level, switch to AspectJ mode. This is particularly useful for private method transactions with older Spring versions that throw a tantrum with the default proxy:
With AspectJ, @Transactional
works even for non-public methods. Simply apply @Transactional
at the class level or configure AspectJ pointcuts to hit bullseye every time.
Manual transaction control: you're the boss
If automatic transaction management isn't sufficient, manually control your transactions. Harness the power of Spring's Transaction API and be the boss of your transactions. Use either TransactionTemplate
or TransactionAspectSupport
to your convenience:
If you suspect a transaction could fail, catch exceptions and roll back:
Ensuring transaction consistency: the right propagation
Different propagation settings control how transactions propagate. Use REQUIRED
, REQUIRES_NEW
, or NESTED
etc., based on your business needs. Choosing the right propagation level can help you achieve transaction consistency:
If class methods call each other and need to be transactional, apply @Transactional
at the class level:
Dynamic objects and cglib limitations
When your application creates dynamic objects or uses cglib for proxying, remember:
- Proxies for dynamic objects may behave differently.
- Cglib proxies can't proxy final methods, leaving them non-transactional.
Configure your Spring to select the right strategy for your proxying needs:
Was this article helpful?