I have a set of @Service
beans which inherit core functionality from an abstract class. I marked each of the concrete sub-class services with @Service
and @Transactional
. The abstract super class contains the public entry point method for each of these services. In other words, I have something similar to the following:
abstract class AbstractService { public void process() { // Do common initialisation code here processSpecific(); // Do common completion code here } abstract protected void processSpecific(); } @Service @Transactional public class FirstSpecificService extends AbstractService { protected void processSpecific() { // Do specific processing code here } } @Service @Transactional public class SecondSpecificService extends AbstractService { protected void processSpecific() { // Do different specific processing code here } }
The specific code in each concrete sub-class service makes multiple calls to the DAO layer to make changes to the database, which have REQUIRED
as the transactional propagation type.
Now with the services defined as above, I discovered that there was no current transaction inside any of the code of these concrete sub-class services, and each call to the DAO layer was creating a new transaction, doing the changes, committing the transaction and returning.
However, if I annotate the abstract super-class with @Transactional
, then a transaction is created properly, and the sub-calls to the DAO layer all participate in the current transaction.
So my question is, what are the rules for inheriting the @Transactional
behaviour? Why does Spring not use the @Transactional
on the concrete sub-class services that it is actually instantiating? Does the @Transactional
need to be on the super-class in this case because that is where the public entry-point method is?
The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.
It can be inherited by children classes. If that is the case, "Java annotation are not inherited from interfaces.... then the transaction settings are not recognized by the proxy" is not true for @Transactional.
@Transactional(MANDATORY) : fails if no transaction was started ; works within the existing transaction otherwise. @Transactional(SUPPORTS) : if a transaction was started, joins it ; otherwise works with no transaction.
ImplementationWe are now ready to use @Transactional annotation either at the class or method level. @Transactional(value = "myTransactionManager", propagation = Propagation.
From the spring transaction documentation,
Note: In proxy mode (which is the default), only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional!
Even though you have the @Transactional on your concrete implementation and you are calling process method which is actually transactional by your annotation, but the process method calling processSpecific on your sub class is not transactional because of this internal call.
Look into Weaving.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With