Spring Boot – Transaction Management Using @Transactional Annotation

@Transactional annotation is the metadata used for managing transactions in the Spring Boot application. To configure Spring Transaction, this annotation can be applied at the class level or method level. In an enterprise application, a transaction is a sequence of actions performed by the application that together pipelined to perform a single operation. For example, booking a flight ticket is also a transaction where the end user has to enter his information and then make a payment to book the ticket.

Read more

Why Do We Need Transaction Management?

Read more

Let’s understand transactions with the above example, if a user has entered his information the user’s information gets stored in the user_info table. Now, to book a ticket he makes an online payment and due to some reason(system failure) the payment has been canceled so, the ticket is not booked for him. But, the problem is that his information gets stored on the user_info table. On a large scale, more than thousands of these things happen within a single day. So, it is not good practice to store a single action of the transaction(Here, only user info is stored not the payment info).

Read more

To overcome these problems, spring provides transaction management, which uses annotation to handle these issues. In such a scenario, spring stores the user information in temporary memory and then checks for payment information if the payment is successful then it will complete the transaction otherwise it will roll back the transaction and the user information will not get stored in the database.

Read more

@Transactional Annotation

Read more

In Spring Boot, @Transactional annotation is used to manage transactions in a Spring boot application and used to define a scope of transaction. This annotation can be applied to the class level or method level. It provides data reliability and consistency. When a method is indicated with @Transactional annotation, it indicates that the particular method should be executed within the context of that transaction. If the transaction becomes successful then the changes made to the database are committed, if any transaction fails, all the changes made to that particular transaction can be rollback and it will ensure that the database remains in a consistent state.

Read more

Note: To use @Transactional annotation, you need to configure transaction management by using @EnableTransactionManagement to your main class of Spring Boot application.

Read more

Configure Transaction in Spring Boot

Read more

In this example, we will create an application to store user information along with his address information and will use spring transaction management to resolve the transaction break problem.

Read more

The @Transactional annotation allows you to define transaction boundaries declaratively. For those looking to deepen their understanding of Spring Boot’s features, the Java Backend course covers essential security practices for safeguarding your applications.

Read more

Step By Step Implementation of Transaction Management

Read more

Step 1: Create A Spring Boot Project

Read more

In this step, we will create a spring boot project. For this, we will be using Spring Initializr.

Read more

Step 2: Add Dependencies

Read more

We will add the required dependencies for our spring boot application.

Read more
Read more

Step 3: Configure Database

Read more

Now, we will configure the database in our application. We will be using the following configurations and add them to our application.properties file.

Read more
Read more

Step 4: Create Model Class

Read more

In this step, we will create our model class. Here, we will be creating two model classes, Employee and Address. While creating the model class we will be using Lombok Library.

Read more

Employee.java

Read more
Read more

Address.java

Read more
Read more

Step 5: Create a Database Layer

Read more

In this step, we will create a database layer. For this, we will be creating EmployeeRepository and AddressRepository and will be extending JpaRepository<T, ID> for performing database-related queries.

Read more

EmployeeRepository.java

Read more
Read more

AddressRepository.java

Read more
Read more

Step 6: Create a Service Layer

Read more

You can use @Transactional annotation in service layer which will result interacting with the database. In this step, we will create a service layer for our application and add business logic to it. For this, we will be creating two classes EmployeeService and AddressService. In EmployeeService class we are throwing an exception.

Read more

EmployeeService.java

Read more
Read more

AddressService.java

Read more
Read more

Step 7: Create Controller

Read more

In this step, we will create a controller for our application. For this, we will create a Controller class and add all the mappings to it.

Read more

Controller.java

Read more
Read more

Step 8: Running Our Application

Read more

In this step, we will run our application. Once, we run our application using hibernate mapping in our database required tables will be created.

Read more
Read more

As we can see in logs, our table has been created. We can also confirm it by looking at our database.

Read more
Read more

Now, we will request our application for adding an employee to it, using postman. To learn more about postman please refer to Postman – Working, HTTP Request & Responses. Once, we hit the request, the request moves from the controller to the service layer where our business logic is present.

Read more
Read more

As we can see in the above response we have added an employee. We can also check our database for employee data and address data.

Read more
Read more

Similarly, we can also check for address data.

Read more
Read more

Step 9: Problem Without Transaction Management

Read more

In the EmployeeService class, we initialize the address object to NULL. Consequently, the employee’s details cannot be stored in the database due to the null address object. However, as we are not employing transaction management, the employee basic information will persisted in the database. The address details are omitted because of the null value.

Read more

Note: Applying the @Transactional annotation to a method will not trigger a rollback of any operation if @EnableTransactionManagement is not used.

Read more
Read more

Now, we will delete our table from the database and again run our application and will request the application to create an employee.

Read more

we have initialized the address object as null and requested the application, we have an employee created in the database but the address information is not, as we have received a null pointer exception. But, this is not good practice in transaction management, as employees should be saved only when the address is saved and vice-versa.

Read more

Step 10: Transaction Management

Read more

To overcome this problem, we will use @Transactional annotation. This will ensure that the transaction should be complete. That is, either both employee and address data should be stored or nothing will get stored. For using transaction management, we need to use @EnableTransactionManagement in the main class of our spring boot application and also, and we need to annotate our addEmployee() method in EmployeeService class with @Transactional annotation.

Read more

TransactionManagementApplication.java

Read more
Read more

Step 11: Running Application

Read more

Now, we have enabled transaction management for our application. We will again delete the tables from our database and request our application to add an employee.

Read more
Read more

As we can see in the above media file, this time the employee data do not get stored in the database, nor did the address data. This way the spring has handled the transaction that both employees and address data gets stored or no data gets stored.

Read more

Conclusion

Read more

In this article, we have learned basic configuration of transaction management using in a Spring Boot application. Also we have covered @Transactional and @EnableTransactionManagement annotation and it’s uses with a step by step implementation in a spring boot application.

Read more

Best Practices of using@Transactional in Spring Boot

Read more

What is the difference between @Transactional and @Transactional(propagation = Propagation.REQUIRES_NEW)?

Read more

@Transactional creates a transaction if none exists or joins an existing transaction if one is already active.

Read more

Where as

Read more

@Transactional(propagation = Propagation.REQUIRES_NEW) creates a new transaction, suspending the current transaction (if one exists).

Read more
Read more

methodA() is marked with @Transactional and calls methodB(), which is marked with @Transactional(propagation = Propagation.REQUIRES_NEW). When methodA() is invoked, Spring creates a transaction and propagates it to methodB(). However, because methodB() has a REQUIRES_NEW propagation setting, it creates a new transaction, suspending the current transaction in methodA().

Read more

What happens if a @Transactional method calls another @Transactional method?

Read more

By default, Spring uses a “proxy-based” approach to manage transactions. If a @Transactional method calls another @Transactional method within the same class, the call is made to the original instance (not the proxy) and the transactional behavior is not applied.

Read more
Read more

How does Spring handle transactions when calling a method on a different bean?

Read more

When calling a method on a different bean, Spring creates a new proxy around the target bean, which allows it to manage the transactional behavior. The behavior of the transaction is determined by the propagation settings of the @Transactional annotation on the calling method.

Read more
Read more

methodA() calls methodB() on a different bean (OtherService). When methodB() is invoked, Spring creates a new proxy around the target bean and applies the transactional behavior based on the propagation settings of the calling method (methodA()).

Read more

What happens when a method marked with @Transactional throws an unchecked exception?

Read more

When a method marked with @Transactional throws an unchecked exception, Spring will automatically roll back the transaction by default. This behavior ensures that data changes made in a transaction will not be persisted in the database if an error occurs.

Read more
Read more

In the above example, the updateUser() method is marked with @Transactional and updates the email address of a user in the database. However, the method also throws an unchecked exception after saving the changes to the database. Because the exception is unchecked, Spring will roll back the transaction and discard the changes made to the user's email address.

Read more

If you want to change the default behavior and allow the transaction to commit even if an unchecked exception occurs, you can add the noRollbackFor attribute to the @Transactional annotation:

Read more
Read more

We’re telling Spring not to roll back the transaction if a RuntimeException occurs. This can be useful in some cases where you want to keep the changes made within the transaction even if an error occurs.

Read more

What is the default rollback behavior of a @Transactional method?

Read more

@Transactional method will roll back the transaction on any unchecked exception. You can customize this behavior using the rollbackFor or noRollbackFor properties of the @Transactional annotation.

Read more
Read more

methodA() is marked with @Transactional(rollbackFor = {Exception.class}). This means that the transaction will be rolled back if any exception of type Exception (or its subclasses) is thrown. If an exception of a different type is thrown, the transaction will not be rolled back.

Read more

Can you use @Transactional on private methods?

Read more

No, @Transactional only works on public methods. Spring creates a proxy around the public methods of a bean to manage the transactional behavior. Private methods are not visible to the proxy and therefore cannot be wrapped in a transactional context.

Read more
Read more

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. Consider the use of AspectJ if you need to annotate non-public methods.

Read more

How does the @Transactional annotation handle concurrency issues?

Read more

Concurrency issues can occur when multiple threads access the same data simultaneously, leading to inconsistencies and data corruption. Spring Boot’s @Transactional annotation provides a mechanism for handling concurrency issues by serializing transactions that modify the same data, preventing multiple threads from modifying the same data at the same time.

Read more

NOTE ** The default isolation level used by the @Transactional annotation in Spring is Isolation.DEFAULT. This means that Spring will use the default isolation level of the underlying data source, which is typically “read committed” for most databases. This default behavior can prevent most concurrency issues by ensuring that transactions do not interfere with each other.

Read more
Read more

The updateUser() method is marked with @Transactional and updates a user's email address in the database. When multiple threads attempt to modify the same user's email address at the same time, Spring will ensure that only one thread can modify the data at any given time by serializing the transactions.

Read more

Did you like this story?

Please share by clicking this button!

Visit our site and see all other available articles!

Influencer Magazine UK