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)
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.
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.
@Transactional annotation is used when you want the certain method/class(=all methods inside) to be executed in a transaction.
Thanks to skaffman for his effort. Finally I think I got the behaviour:
<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). 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.
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.
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