Monday, May 18, 2020

Transaction Management in Spring

This post gives an overview of Spring transaction management, how abstraction is achieved in Spring transaction and how to do programmatic transaction management or declarative transaction management in Spring.


What is transaction

In an application transaction is a sequence of events with all or none proposition. That is either all the events participating in the transaction should happen or none. Transaction demarcates the boundaries and all the statements with in those boundaries are bound by all or none proposition and executed as a single unit of work.

Problems with managing transactions

If you manage transaction on your own or use EJB container managed transaction you choose the transaction as per your requirement i.e. if your using JDBC then you choose the transaction management API for JDBC, for Hibernate you will choose the hibernate transaction management API and for Application server with global transaction you will go with JTA (Java transaction API).

With this approach, if you are using global transactions, where you have multiple transactional resources (like relational databases and message queues) you will manage transaction through JTA.

If you are using local transactions (like a transaction associated with a JDBC connection) you will use JDBC transaction management API. Problem with local transactions is that they cannot work across multiple transactional resources. For example, code that manages transactions using a JDBC connection cannot run within a global JTA transaction. Another problem with local transactions is that they are invasive i.e. you will have all transaction code with in your code.

As example with JDBC transaction you will have something like following in your code.

try{
 connection.setAutoCommit(false);

 statements that are part of transaction
 ---
 ---

 connection.commit(); // for committing transaction
}catch(SQLException exp){
 // transaction rollback
 connection.rollback();
}

Transaction Management in Spring

Spring Framework provides a consistent abstraction for transaction management. Spring transaction management acts as an abstract layer hiding the underlying transaction management API thus providing a consistent programming model across different transaction APIs such as Java Transaction API(JTA), JDBC, Hibernate, and Java Persistence API (JPA).

With Spring transaction management you write your code once and it can be used in different transaction management strategies in different environments.

Spring transactions are also a significant improvement over the EJB transactions as you can use POJOs with Spring transactions. You don’t even need an Application server for Spring transactions unless you are using distributed transactions in which case you need JTA capabilities.

How abstraction is achieved in Spring transaction management

Abstraction in Spring transaction management is achieved through org.springframework.transaction.PlatformTransactionManager interface.

public interface PlatformTransactionManager {
 TransactionStatus getTransaction(TransactionDefinition definition)
             throws TransactionException;
 void commit(TransactionStatus status) throws TransactionException;
 void rollback(TransactionStatus status) throws TransactionException;
}

In the interface, getTransaction() method returns a TransactionStatus object which represents the status of a transaction, it might represent a new transaction or an existing transaction if a matching transaction exists. The parameter passed in getTransaction() method is an instance of TransactionDefinition.

TransactionDefinition defines the properties of the Spring transaction, which are as follows.

  • Propagation- Defines the propagation behavior of the transaction. For example you can specify a behavior so that code can continue running in the existing transaction or the existing transaction can be suspended and a new transaction created.
  • Isolation- This property defines the extent to which this transaction is isolated from the work of other transactions. For example, can this transaction see uncommitted writes from other transactions?
  • Timeout- How long this transaction runs before timing out and being rolled back automatically by the underlying transaction infrastructure.
  • Read-only status- A read-only transaction can be used when your code reads but does not modify data.

Refer Spring Transaction Attributes- Propagation And Isolation Level Settings to know about the various propagation and isolation level settings in the Spring transaction management.

Defining Transaction manager in Spring transactions

As we have seen it is the PlatformTransactionManager through which the transaction is abstracted in Spring transaction management but you do need to define the correct PlatformTransactionManager implementation.

PlatformTransactionManager implementations normally require knowledge of the environment in which they work: JDBC, JTA, Hibernate, and so on. Following are the implementation classes for different environments.

PlatformTransactionManager implementations in Spring framework

  • DataSourceTransactionManager- PlatformTransactionManager implementation for a single JDBC DataSource.
  • HibernateTransactionManager- PlatformTransactionManager implementation for a single Hibernate SessionFactory.
  • JmsTransactionManager- PlatformTransactionManager implementation for a single JMS ConnectionFactory.
  • JpaTransactionManager- PlatformTransactionManager implementation for a single JPA EntityManagerFactory.
  • JtaTransactionManager- PlatformTransactionManager implementation for JTA, delegating to a backend JTA provider.
  • WebLogicJtaTransactionManager- Special JtaTransactionManager variant for BEA WebLogic (9.0 and higher).
  • WebSphereUowTransactionManager- WebSphere-specific PlatformTransactionManager implementation that delegates to a UOWManager instance
Here are some examples showing how TransactionManager can be defined for different environments.

TransactionManager For JDBC in Spring

Defined by having a reference to the defined DataSource.

<bean id="txManager" class=
"org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource"/>
</bean>

TransactionManager For Hibernate in Spring

<bean id="txManager" class=
"org.springframework.orm.hibernate5.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory"/>
</bean>

TransactionManager For JPA in Spring

<bean id="txManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
  <propertyname="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

TransactionManager For JTA in Spring

<bean id="txManager" class=
"org.springframework.transaction.jta.JtaTransactionManager" />

Spring Transaction management types

Spring Transaction management has support for both programmatic transaction management and declarative transaction management.

Programmatic transaction management

Spring Framework provides two means of programmatic transaction management-

  • Using TransactionTemplate.
  • Using a PlatformTransactionManager implementation directly.

Mostly declarative transaction that too using annotation is used so we'll focus on that. If you want to use TransactionTemplate then you can configure it as follows by providing the reference of the Transaction manager.

<propertyname="transactionTemplate">
<bean class="org.springframework.transaction.support.
TransactionTemplate">
<property name="transactionManager"
ref="txManager" />
</bean>
</property>

Declarative transaction management in Spring

By using Declarative transaction for Spring transaction management you keep transaction management separate from the business code. You can define declarative transactions using annotations or XML based configuration using AOP.

The annotation used for Declarative transaction management is @Transactional annotation. You can place the @Transactional annotation before an interface definition, a method on an interface, a class definition, or a public method on a class.

To make Spring framework aware of the @Transactional annotation you will have to define <tx:annotation-driven/> element in your XML configuration.

<tx:annotation-driven transaction-manager="txManager"/>

If you using Java configuration then you can enable @Transactional annotation support by adding @EnableTransactionManagement to your config class.

@Configuration
@EnableTransactionManagement
public class AppConfig{
    ...
    ...
}

Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional annotation, as opposed to annotating interfaces.

@Transactional settings in Spring framework

You can provide transaction properties like propagation behavior, isolation level along with @Transactional annotation. Full list of the properties of the @Transactional annotation are as follows-

  • propagation- Optional propagation setting.
  • isolation- Optional isolation level. Only applicable to propagation REQUIRED or REQUIRES_NEW.
  • timeout- Optional transaction timeout. Only applicable to propagation REQUIRED or REQUIRES_NEW. Defined in seconds using an int value.
  • readOnly- Read/write vs. read-only transaction. Only applicable to REQUIRED or REQUIRES_NEW.
  • rollbackFor- Optional array of exception classes that must cause rollback.
  • rollbackForClassName- Optional array of names of exception classes that must cause rollback.
  • noRollbackFor- Optional array of exception classes that must not cause rollback.
  • noRollbackForClassName- Optional array of names of exception classes that must not cause rollback.
The default @Transactional settings are as follows:
  • Propagation setting is PROPAGATION_REQUIRED.
  • Isolation level is ISOLATION_DEFAULT.
  • Transaction is read/write.
  • Transaction timeout defaults to the default timeout of the underlying transaction system, or to none if timeouts are not supported.
  • Any RuntimeException triggers rollback, and any checked Exception does not.

Example using @Transactional annotation

@Transactional(readOnly = true, propagation=Propagation.SUPPORTS)
public class TestService implements FooService {
 public Foo getValue(String Id) {
  // do something
 }
 // these settings have precedence for this method
 @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, timeout=60, rollbackFor=ValueNotFoundException.class)
 public void updateValue(Person person) {
  // do something
 }
}

Here at the class level TestService class is annotated with @Transactional annotation which is for all the methods in the class that all the methods will support transaction and will be read only. Method updateValue overrides it by having its own @Transactional annotation which requires a new transaction, read only is false and transaction is rolled back if ValueNotFoundException is thrown.

That's all for this topic Transaction Management in Spring. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Spring Transaction Management JDBC Example Using @Transactional Annotation
  2. Data Access in Spring Framework
  3. Insert\Update Using NamedParameterJDBCTemplate in Spring Framework
  4. Spring MVC Form Example With Bean Validation
  5. Spring Batch Processing Using JDBCTemplate batchUpdate() Method

You may also like-

  1. Difference Between component-scan And annotation-config in Spring
  2. How to Inject Null And Empty String Values in Spring
  3. Internationalization (i18n) Using MessageSource in Spring
  4. Circular Dependency in Spring Framework
  5. Heap Memory Allocation in Java
  6. Stream API in Java 8
  7. Creating Custom Exception Class in Java
  8. Installing Hadoop on a Single Node Cluster in Pseudo-Distributed Mode