Wednesday, April 24, 2024

Spring Boot @Transactional Annotation Example - How to Manage Transactions using Spring Framework?

One of the most essential parts of Spring MVC is the @Transactional annotation, which provides support for transaction management and allows developers to concentrate on coding business logic rather than worrying about data integrity in the event of system failures. In other words, @Transactional annotation  simplifies the process of transaction management and it allows you to specify transactional behavior directly within your code, typically at the service layer. You can put @Transactional annotation both at the class level and method level. When you put the @Transacational at the class level, it applies to all the public method of the class but when you put the @Transacational annotation at the method level. It only applies to that method. 

Also, Spring Framework provides declarative and programmatic transaction management, and you can choose between convenience and control, depending on the requirement. Declarative transaction management is easier and suitable in most cases, but in some cases, you want fine-grain control, and that time you can use the declarative transaction. 

We'll see examples of both declarative and programmatic transaction management using Spring Framework and Spring Boot in this article. 


But before that, let's see key points of transaction management using Spring Framework,

1. You can put @Transacational at the class or method level. When you put at the class level it applies to all the public method of that class.

2. By default @Transacational annotation create a new transaction if none exists already but if there is already a transaction then it joins the existing transaction. However you can customize this behavior by using attributes like propagation, isolation, readOnly, timeout, and rollbackFor.

3. Spring allow allows you to configure and control rollback behavior. You can specify the condition on which rollback should occur by using attributes like rollbackFor and noRollbackFor.

4. By default Spring rollback a transaction if a RuntimeException or unchecked exception occurs but it doesn't rollback in case of checked exception. Though, you can override this behavior by using attribute rollbackFor

5. In order to enable the transaction just putting @Transactional is not enough you also need to configure a transaction manager bean in your Spring configuration file using XML or Java config. This bean manages the underlying transaction infrastructure such as JDBC or JTA. 

6. Internally, Spring uses proxy to implement transaction behavior. For example when you annotate a method with @Transactional annotation, Spring uses proxy-based Aspect Oriented Programming to create a proxy around that method. It then intercept the method calls to manage the transactions.  

7. Spring Framework support both declarative and programmatic transaction management. For example while @Transactional is used for declarative transaction management, it also provide APIs like TransactionTemplate or PlatformTransactionManager implementations which can be used to support programmatic transaction management.

8. Spring's @Transactional annotation supports various transaction technologies like JDBC, Hibernate, Spring Data JPA, JDO, JTA, and others.

These are few important points about @Transactional and transaction management in Spring and Spring Boot which I believe every Java developer should know and familiar of. 

So in this tutorial, let’s first discuss database transactions, and then we'll see how the spring framework can manage transactions in Java applications. 

A database transaction is a sequence of actions that are treated as a single unit of work. The concepts of transactions can be described with the following four key properties called ACID properties.

1. Atomicity – This refers to either the entire sequence of operation is successful or unsuccessful.

2. Consistency – Consistency of referential integrity of the database.

3. Isolation – There may be many transactions processing with the same data set simultaneously.

4. Durability – Results of the transactions can not be erased from the database due to system failures.







Read-write and read-only transaction routing in Spring

A real RDBMS database system like MySQL, PostgreSQL, SQL Server, or Oracle will guarantee all four properties for each transaction. Spring framework is also used to provide an abstract layer on top of the different underlying transaction management APIs. 

Basically, there are two distinct ways to configure Transactions in Spring based Java applications, either by using annotations, or by using AOP, each with its own advantages. 

We're going to discuss the more common annotation-config here.

@Configuration
@EnableTransactionManagement
public class PersistenceJPAConfig{

@Bean
public PlatformTransactionManager transactionManager(){
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(
    entityManagerFactoryBean().getObject() );
    return transactionManager;
}

But if you use the Spring boot project with this dependency spring-boot-starter-data-jpa, then transaction management will be enabled by default.

Spring @Transactional Example - How to Manage Transaction using Spring Framework? 



2. The @Transactional Annotation

You can annotate a bean with @Transactional either at the class or method level.

import org.springframework.stereotype.Service;
import javax.transaction.Transactional;

@Service
@Transactional
public class ProductService {

}

From the above code, you can see that @Transactional annotation enables,

1. Rollback rules of the transactions

2. Transaction should be read-only

3. Isolation level of the transaction

4. Timeout of the operation wrapped by transaction


Note: The checked exception does not trigger a rollback of the transaction. This is one of the important things to know and remember as it can cause issues. You can further read comprehensive spring books or join comprehensive courses to learn more about transaction management in the spring framework. 

 




3. Transaction Management in Spring Framework

When it comes to transaction management, there are two 2 ways to achieve it. Spring Programmatic transaction management and Spring Declarative transaction management. Will have a quick introduction to both these methods.


3.1  Spring Programmatic Transaction Management.

Transaction management code needs to be explicitly written, and it is tightly bound to business logic in this case. This allows you to manage the transaction with the help of programming in your source code. That gives you extreme flexibility, but it is difficult to maintain.

StudentTransaction studentTransaction = entityManager.getTransaction();
try {
    studentTransaction.begin(); //start of the first student transaction
   //this is the place that used to create students and link them
  /* register student - query 1
      create student
     link note to the user - query 2 */

    //Commit Student Transaction
      studentTransaction.commit();
    } catch(Exception exception) {
          //Rollback Student Transaction
          userNoteTransaction.rollback();
        throw exception;
}


3.2 Spring Declarative Transaction Management

Instead of hard coding in your source code, you can handle the transaction with the help of settings. To manage transactions, you only need to utilize annotations or XML-based settings. This also allows the transaction management and business code to be separated. Some of the steps associated with the declarative transaction are,

1. If the method has been included in the transactional configuration, then the created advice will begin the transaction before calling the method

2. Target method will be executed in a try/catch block.

3. If the method finishes normally, the AOP advice commits the transaction successfully; otherwise, it performs a rollback.

@Transactional
public void addStudentToSpecificClass() {
/* register student - query
create new student
link student to class - query 2 */
}


Different types of Transaction Propagation in Transaction Management specify whether or not the related component will participate in the transaction and what occurs if the caller component/service has or has not previously created/started a transaction.

That's all about how to use @Transactional annotation in Java with Spring Framework. Spring provide support for both programmatic and declarative transaction management using TransactionTemplate and @Transactional annotation. In most cases, you should be better of using @Transactional annotation as its simple and easy but if you need more control then you can use TransactionTempalte class. It's also important to note that you need to define a transaction manager bean in Spring configuration to manage underlying transaction infrastructure like JPA or JDBC.

It's also best practice to carefully design the transaction boundaries and understand the implication of transactional behavior in your applications' performance and data consistency. 

A poorly designed or implemented transactional behavior can lead to serious issues like deadlock, live lock, poor performance and inconsistent data. Hence its important that you use transaction only when you really need it and carefully evaluate with your peers or technical lead to avoid any issue in production. 


Other Spring Framework articles you may like to explore 

Thanks for reading this article so far. If you like these Spring @Transactional annotation tutorials and examples then, please share them with your friends and colleagues. If you have any questions or feedback, then please drop a note.

P. S. - If you are new to Spring and Spring MVC and looking for free online courses to kickstart your learning then I highly recommend you to check these free Spring MVC courses. It also includes free core spring and spring boot courses from Udemy and Coursera. 

1 comment: