Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Transaction propagation issue

I am using Transaction management with Spring and Hibernate. My situation is as follow:
I have got bean A which is sorrounded by transaction and it call bean B which is defined with transaction including the attribute 'PROPAGATION_REQUIRED'

B in this case doesn't open new transaction but uses the exsiting one (saw in the logs: 'Participating in existing transaction'). However in case the method in B will throw a runtimeException, on its way back to A it will dirty the transaction and will cause it to be marked for roll-back, even if the external method of A will catch the exception and won't throw it away. I think that this behavior is wrong, in this case I want A to control the transaction and B should not interrupt the transaction in any case.
Is there any way to define B to open transaction if no transaction defined but DO NOTHING if it is already inside an exising transaction and let the upper level make the decision whether to commit or roll-back?

See more responses about this issue in a thread in Spring community here.

like image 313
Spiderman Avatar asked Aug 26 '10 08:08

Spiderman


3 Answers

When you configure your Spring transaction manager, you can set the property called "globalRollbackOnParticipationFailure". If set to false, an exception occuring in a method that participates in an existing transaction will no mark the transation for rollback. The transaction is only marked for rollback if the exception if thrown out of the method that started the transaction.

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
    <property name="globalRollbackOnParticipationFailure" value="false" />
</bean>

See the JavaDoc for more info.

like image 36
Christophe L Avatar answered Nov 10 '22 05:11

Christophe L


Theoretically it is possible, but not within the standard means of Spring's Transaction aspects. You would need to create your own aspect that duplicates the spring standard functionality, extending it for your special case. Perhaps it will even be possible to extend the original aspect they use.

(Probably you will have to define a custom annotation though, because you can neither override the @Transactional attribute nor extend the Propagation enum.)

Here are some pointers:

  • Spring Transaction Management, especially:
  • Transaction propagation
  • Using @Transactional
  • Using @Transactional with AspectJ

Also, you should consider reading the book AspectJ in Action, even if you just want to use Spring AOP, as it gives a very good overview.

A good starting point is to download the sources of the spring-aspects jar, see what they are doing there and provide your own extension of either org.springframework.transaction.aspectj.AbstractTransactionAspect or org.springframework.transaction.aspectj.AnnotationTransactionAspect

To sum it up: I'm sure it can be done, but it will take a lot of work. The Spring Transaction API is pretty good as it is though. Maybe you should learn to live with it's limitations. If not: start hacking (see above)

like image 24
Sean Patrick Floyd Avatar answered Nov 10 '22 03:11

Sean Patrick Floyd


It looks like Propagation.NESTED is something that can help you:

  • If B fails, the transaction started with A (and continued with B) will correctly rolledback to savepoint before B is called without touching A.
  • When B is committed, only savepoint is released, nothing else is issued to DB. Bascailly that means that changes made by B are "merged" into transaction A.
  • After B finishes, in any above mentioned case A can decide weather to continue and commit (that will be a real commit to DB which will include all changes by A and B [if it committed]) or to rollback (that will rollback the transaction up to the state when it was created invalidating all changes by A + B).
like image 185
dma_k Avatar answered Nov 10 '22 04:11

dma_k