As part of this article, we will try to understand how Spring Boot transaction management works with the SUPPORTS propagation level.
Table of contents
Propagation level
The propagation level in spring decides if the spring has to create a new transaction or if the same transaction can be used to perform a database operation.
A transaction is a single unit of work. In a transaction, there can be multiple steps and we have to make sure either all the steps are successful or none should be successful. We know @Transactional annotation helps to achieve transaction management in spring.
Please follow this article before moving further spring boot transaction management here you will understand what is a transaction and how transaction management works in spring-boot with a proper example. This article will be an extension of the above-mentioned article.
Supports Propagation
- Supports Propagation means if a transaction is already available then make use of the same transaction.
- If the transaction is not available then don’t create a new transaction instead run that piece of code without any transaction.
In our previous example, we created 2 controllers: EmployeeController and ManagerController.
ManagerController saves only Manager. The below service method is called from ManagerController.
@Override public String saveManager() { String response = "Manager Saved"; Manager manager = new Manager("Suraj"); managerDao.save(manager); System.out.println(response); return response; }
We will update the above method with Supports propagation.
package com.getinputs.h2database.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.getinputs.h2database.dao.ManagerDao; import com.getinputs.h2database.model.Manager; import com.getinputs.h2database.service.ManagerService; @Service public class ManagerServiceImpl implements ManagerService { @Autowired private ManagerDao managerDao; @Override @Transactional(propagation = Propagation.SUPPORTS) public String saveManager() { String response = "Manager Saved"; Manager manager = new Manager("Suraj"); managerDao.save(manager); System.out.println(response); return response; } }
We will update the application.properties with log4j properties so that we will get a better insight into whether a transaction is created or not.
application.properties # DB Properties spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect # Logging Properties logging.level.ROOT=INFO logging.level.org.springframework.orm.jpa=DEBUG logging.level.org.springframework.transaction=DEBUG
Once the above changes are done we will build and run the application.
-> mvn clean install -DskipTests
-> mvn spring-boot:run
Trigger http://localhost:8080/manager
Output : Manager Saved
From the above logs, we can conclude that a transaction is created but it is created within the internal JPA module. The transaction is not created in the ManagerService -> saveManager method. Hence we can conclude SUPPORTS propagation does not create a new transaction in the service layer.
Steps after we trigger the manager Url
1 ) Request reaches the ManagerController and the saveManager method gets triggered.
2 ) saveManager method in ManagerController makes a call to the saveManager method of ManagerServiceImpl.
3 ) Spring realizes the saveManager method is annotated with @Transactional annotation and Propagation.SUPPORTS. Here Spring checks if there is an existing transaction available but as of now there is no transaction available hence the saveManager method gets executed without any transaction.
4 ) Manager object is saved in the database with no transaction.
Now to understand the above situation in a better way we will make the changes in the EmployeeServiceImpl.
EmployeeController saves Employee as well as Manager. The below service method is called from EmployeeController.
@Override public String saveEmployeeAndManager() { String response = "Employee and Manager Saved."; Employee employee = new Employee("Surya", 50000); employeeDao.save(employee); managerService.saveManager(); // This code calls Manager service method return response; }
We will update the above method with the Required propagation.
package com.getinputs.h2database.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.getinputs.h2database.dao.EmployeeDao; import com.getinputs.h2database.model.Employee; import com.getinputs.h2database.service.ManagerService; import com.getinputs.h2database.service.EmployeeService; @Service public class EmployeeServiceImpl implements EmployeeService { @Autowired private EmployeeDao employeeDao; @Autowired private ManagerService managerService; @Override @Transactional(propagation = Propagation.REQUIRED) public String saveEmployeeAndManager() { String response = "Employee and Manager Saved."; Employee employee = new Employee("Surya", 50000); employeeDao.save(employee); managerService.saveManager(); return response; } }
Once the above changes are done we will build and run the application
-> mvn clean install -DskipTests
-> mvn spring-boot:run
Trigger http://localhost:8080/employee
Output: Employee and Manager Saved.
From the above logs, we can conclude that both the employee and manager get saved in the database in a single transaction.
Steps after we trigger the employee Url
1 ) Request reaches the EmployeeController and the saveEmployeeAndManager method gets triggered.
2 ) saveEmployeeAndManager method in EmployeeController makes a call to saveEmployeeAndManager method of EmployeeServiceImpl.
3 ) Spring realizes the saveEmployeeAndManager method is annotated with @Transactional annotation and Propagation.REQUIRED. Here Spring checks if there is any existing transaction available but as of now there is no transaction available hence spring creates a new transaction [ TRANSACTION-1 ]
4 ) Employee object is saved in the database under TRANSACTION-1.
5 ) saveEmployeeAndManager method of EmployeeServiceImpl makes a call to saveManager method of ManagerServiceImpl.
6 ) Spring realizes the saveManager method is also annotated with @Transactional annotation and Propagation.SUPPORTS. Here Spring checks if there is any existing transaction available. Now spring comes to know there is already a transaction available TRANSACTION-1. Now since the current saveManager method is having a Supports propagation so spring does not create a new transaction and uses the same TRANSACTION-1 to save the Manager object.
If you want to get information on the REQUIRED propagation level please check this article : Spring boot transaction management with required propagation level.
Github repository link
https://github.com/getinputs/samples/tree/main/transaction-management-supports-propagation
In this article, we have covered a Sample application on how the spring boot transaction management works with the Supports Propagation level. I hope you found this article interesting and valuable. Please share this article with your friends and help me grow. If you are having any concerns or questions about this article please comment below. If you want to get in touch with me please visit the Contact Me page and send an email.
1 thought on “Spring boot transaction management with Supports Propagation level”