Spring’s @Transactional Important Points

Spring has a great way to handle transactions using @Transactional annotation. However, there are a few gotchas that one needs to watch out for. Without a good understanding of how Spring treats transactions, you can run into some unexpected and undesirable behavior. For an in depth study of the topic refer to the Sping Spring Documentation on transaction management. I will try to summarize a few important points.

1. Spring provides support for transactions using AOP Proxies

Spring AOP Proxy http://docs.spring.io/spring/docs/4.0.2.RELEASE/spring-framework-reference/htmlsingle/#tx-decl-explained

It means that you are not calling a method directly but through a proxy. This is a very important point to remember when defining transaction boundaries. In an event where a service method calls another method in the same class with a different propagation setting (PROPAGATION_REQUIRES_NEW for example), that setting will be ignored since the call is made internally. If you are not aware of the AOP concept the behavior of those methods will most likely not match your expectations.

In order to let Spring manage transactions you have to add @EnableTransactionManagement to your Java config class or if using XML configuration add <tx:annotation-driven/> . (Don’t forget the namespace: xmlns:tx="http://www.springframework.org/schema/tx"

2. Spring automatically rolls back transactions for unchecked (Runtime) exceptions.

When a Runtime exception is encountered Spring marks the current transaction for a rollback. Perhaps the most confusing part of such rollbacks is seeing this message "UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only". This is an expected behavior but can be confusing if one does not understand what is happening here. In a case when a transactional method calls another transactional method in a different class and that inner call throws a Runtime exception, the entire transaction will be rolled back. This will happen whether or not you catch the Exception in the calling class. If the outer class rollback is not desired, you should either execute the inner class in a new transaction (using a different propagation) or use a noRollBackFor attribute of the @Transactional annotation. Here is the excerpt from Spring documentation on the subject.

When the propagation setting is PROPAGATION_REQUIRED, a logical transaction scope is created for each method upon which the setting is applied. Each such logical transaction scope can determine rollback-only status individually, with an outer transaction scope being logically independent from the inner transaction scope. Of course, in case of standard PROPAGATION_REQUIRED behavior, all these scopes will be mapped to the same physical transaction. So a rollback-only marker set in the inner transaction scope does affect the outer transaction’s chance to actually commit (as you would expect it to).

However, in the case where an inner transaction scope sets the rollback-only marker, the outer transaction has not decided on the rollback itself, and so the rollback (silently triggered by the inner transaction scope) is unexpected. A corresponding UnexpectedRollbackException is thrown at that point. This is expected behavior so that the caller of a transaction can never be misled to assume that a commit was performed when it really was not. So if an inner transaction (of which the outer caller is not aware) silently marks a transaction as rollback-only, the outer caller still calls commit. The outer caller needs to receive an UnexpectedRollbackException to indicate clearly that a rollback was performed instead.

3. Do not use @Transactional annotation methods with private, protected or default modifiers.

This goes along with the first point of how Spring manages transactions. Adding annotations to the methods with the private, protected or default modifiers will not throw an exception. The annotation, however, will be ignored.

Conclusion

Spring Framework provides a powerful way to manage database transactions. Using annotations to define transaction boundaries minimizes coupling thus following good design principles. However, applying @Transactional without the proper understanding of how they behave can have unpredictable and sometimes disastrous results. Carefully study the documentation on the subject to find the best fitting solution to your particular situation. I do believe that understanding the 3 points discussed above will help you avoid most pitfalls while using Spring’s declarative transaction management.

4 thoughts on “Spring’s @Transactional Important Points

  1. Pingback: Maria Smith

  2. I don’t understand why any intelligent, think outside the box, open minded developer someone would choose to use such a technology with all these caveats, workarounds and awkward ‘gotchas’ when much better, logical and more productive technologies are available.
    No wonder new people to Java think it’s a hard language to learn – it’s got nothing to do with the language but the type of frameworks that some people just assume go hand in hand with Java enterprise development – there are better ways people… wake up!

Leave a Reply

Your email address will not be published. Required fields are marked *