Spring boot transaction management with Supports Propagation level

As part of this article, we will try to understand how Spring Boot transaction management works with the SUPPORTS propagation level.

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

supports propagation level

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.

supports propagation level

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.

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”

Leave a Comment