Spring Transaction Handling
Spring Transaction Handling
CODE HOUSE
Transaction Handling
Share
08 May 2021
Transactional Methods
The method executes inside of a transaction, if anything goes wrong in the middle of the method execution, the
transaction will be rolled back, otherwise, it will be committed.
If the method runs within a transaction, the whole method will fail instead of returning 30 comments.
Spring provides comprehensive transaction support, and the following is a very simplified overview of how it
works.
Spring Framework’s transaction support is enabled via AOP proxies. So the caller of the method invokes
the proxy, not the target, and at this point, a transaction is created. Then the target method is invoked,
and on the way back, either the transaction is committed or rolled back.
We are building a Spring Boot application, so most of the configuration is done for me. because I have spring-data
libraries in the classpath, transaction management is enabled by the framework. So, you don’t have to do anything
to enable transaction management.
In order to apply transaction management, all you have to do is add the @Transactional annotation.
The @Transactional annotation is metadata that specifies that an interface, class, or method must have
transactional semantics. For example, “start a brand new read-only transaction when this method is invoked,
suspending any existing transaction”.
There are quite a few settings that can be applied to this annotation. The following table from the documentation
lists all of them.
@Transactional Settings
Array of Class objects, which must be Optional array of exception classes that
rollbackFor
derived from Throwable. must cause rollback.
Array of Class objects, which must be Optional array of exception classes that
noRollbackFor
derived from Throwable. must not cause rollback.
propagation PROPAGATION_REQUIRED
Isolation ISOLATION_DEFAULT
readOnly read/write.
The default timeout of the underlying transaction system, or to none if timeouts are not
timeout
supported.
propagation
These are the transaction propagation behaviours defined by the propagation enum. Let’s look at a couple of
them.
REQUIRED - Supports a current transaction, create a new one if none exists. If there is a transaction already
started, then this method will execute within that, otherwise, a new one will be created.
REQUIRES_NEW - Create a new transaction, and suspend the current transaction if one exists.
readOnly
What happens when the read-only attribute is set to true ? Spring doesn’t handle persistence, so it cannot
define exactly what read-only should do. So this is just a hint to the provider which in this case is hibernate.
According to the documentation, if using hibernate as the JPA provider, when readOnly flag is set to true ,
flushMode on the Hibernate session will be set to NEVER, preventing any changes to data.
Following is the excerpt from the spring data documentation which states this.
“It’s definitely reasonable to use transactions for read only queries and we can mark them as such by setting the readOnly flag. This will
not, however, act as check that you do not trigger a manipulating query (although some databases reject INSERT and UPDATE
statements inside a read only transaction). The readOnly flag instead is propagated as hint to the underlying JDBC driver for
performance optimizations. Furthermore, Spring will perform some optimizations on the underlying JPA provider. E.g. when used with
Hibernate the flush mode is set to NEVER when you configure a transaction as readOnly which causes Hibernate to skip dirty checks (a
noticeable improvement on large object trees).” — Spring Documentation
timeout
javax.transaction.Transactional vs
org.springframework.transaction.annotation.Transactional
Spring transaction management also supports the @Transactional annotation from Java
( javax.transaction.Transactional ) as a drop-in replacement for the @Transactional annotation provided by
Spring. However, it lacks some of the settings available in the one from Spring such as readOnly and timeout
which are quite useful. So I would use Spring’s @Transactional annotation instead of the one from Java.
“Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional annotation,
as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method),
but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited
from interfaces means that if you are using class-based proxies ( proxy-target-class=”true”) or the weaving-based aspect (
mode=”aspectj”), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be
wrapped in a transactional proxy, which would be decidedly bad.”
— Spring Documentation
Don’t worry if you are confused with the above excerpt, it’s all explained below.
Following are the settings or the attributes which can be set on this tag.
transaction-manager
mode
proxy-target-class
order
mode
order
proxyTargetClass
Regardless of the mode of configuration, i.e. either XML or Java based configuration, so long as we have not
specifically set these attributes, the default values apply. So let’s look at each one.
The default value is false. In which case, JDK interface-based proxies are created.
If this attribute is set to true, then CGLIB proxies will be used, which are class-based, and therefore any
@Transactional annotations on interfaces will be ignored.
The mode
There are 2 values that can be applied to the mode attribute. proxy and aspectJ .
The default value of the mode attribute is proxy . It processes annotated beans to be proxied using Spring’s AOP
framework, which would proxy interfaces annotated with @Transactional .
But when the mode is set to aspectJ the interfaces annotated with @Transactional will be ignored.
That’s because,
The aspect that interprets @Transactional annotations is the AnnotationTransactionAspect. When using this aspect, you must annotate
the implementation class (and/or methods within that class), not the interface (if any) that the class implements. AspectJ follows Java’s
rule that annotations on interfaces are not inherited. — Spring Documentation
Keep in mind when using proxy mode which is the default setting.
. only external method calls will be transactional.
even though a method is marked with @Transactional annotation, if it is called within another
method of the same object, it will not have transactional behaviour.
. you should apply the @Transactional annotation only to methods with public visibility.
If you do annotate protected, private or package-visible methods with the @Transactional
annotation, no error is raised, but the annotated method does not exhibit the configured
transactional settings.
So if you want transactional behaviour in either self invocations or non-public methods, consider the use
of aspectJ mode instead of proxy .
I highly recommend reading the documentation for Spring transaction management as we cannot cover
everything here.
Next