Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Annotation-based and xml-based transaction definitions precedence

Tags:

java

spring

I couldn't find a definitive answer to this in the docs, and although there seems to be a logical answer, one can't be sure. The scenario is this - you have a xml-based transaction definition, like:

<tx:advice id="txAdvice" transaction-manager="jpaTransactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

Which advises all service methods. But then you have @Transactional on a concrete class/method, where you want to override the propagation attribute.

It is clear that @Transactional at method-level overrides the same one at class-level, but does it override the <tx:advice> (and actually, the <aop:pointcut>)?

I hope two interceptors won't be created on the same class, (and whichever happens to be first will start the transaction)

like image 732
Bozho Avatar asked Jan 02 '10 09:01

Bozho


People also ask

Is it sufficient to annotate the classes with the @transactional annotation?

It is not sufficient to tell you simply to annotate your classes with the @Transactional annotation, add the line ( <tx:annotation-driven/> ) to your configuration, and then expect you to understand how it all works.

What is the use of @transactional annotation in Spring boot?

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.

What is @transactional used for?

@Transactional annotation is used when you want the certain method/class(=all methods inside) to be executed in a transaction.


2 Answers

Thanks to skaffman for his effort. Finally I think I got the behaviour:

  1. Both <aop:advisor> and @Transactional (together with <tx:annotation-driven>) create a TransactionInterceptor around the target class (the one, whose methods are to be run in transaction).
  2. The advice with a lower order attribute overrides the other one. If no order attribute is specified, the order is undefined. But my tests showed that the one defined latest in the applicationContext.xml takes precedence, although this might not be the case always:

When two pieces of advice defined in different aspects both need to run at the same join point, unless you specify otherwise the order of execution is undefined.

At least this is the behaviour for spring 2.5.6.

like image 53
Bozho Avatar answered Oct 16 '22 12:10

Bozho


After a bit of digging, I think the answer lies in TxAdviceBeanDefinitionParser.doParse. The logic says:

if <tx:attributes> is present then
   parse <tx:attributes> 
else
   instantiate an AnnotationTransactionAttributeSource to determine TX attributes

Given the only thing that reads @Transactional is AnnotationTransactionAttributeSource, that strongly suggests to me that <tx:advice> will consult @Transactional if and only if <tx:attributes> is not specified, so no overriding is possible.

This does seem to contradict Spring's usual "principle of least surprise" approach, since like you I would have expected the annotation to take precedence on a per-class or per-method basis. I would file an issue on their JIRA to get this behaviour changed.

Having said all that, I still think it's worth giving this a try to see what it does, since it may work by some other mechanism.

like image 25
skaffman Avatar answered Oct 16 '22 14:10

skaffman