Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Transactional inheritance rules

Tags:

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?

like image 948
DuncanKinnear Avatar asked Mar 29 '12 03:03

DuncanKinnear


People also ask

How does @transactional work in Spring?

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.

Is transactional annotation inherited?

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.

Is @transactional mandatory?

@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.

Can we use @transactional at class level?

ImplementationWe are now ready to use @Transactional annotation either at the class or method level. @Transactional(value = "myTransactionManager", propagation = Propagation.


1 Answers

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.

like image 76
Kathir Avatar answered Oct 01 '22 04:10

Kathir