Spring(SpringBoot)--Transaction Propagation Mechanism--Application/Instance/Detailed Explanation

1. Introduction

        This article introduces the transaction propagation mechanism in Spring, and illustrates its usage with examples.

        This content is also a common question in Java backend interviews.

2. Overview

Spring specifies seven types of transaction propagation behaviors in the TransactionDefinition interface. The Propagation enumeration refers to these types, and we generally use the Propagation enumeration directly during the development process. The three commonly used items have been bolded.

All the tests here are to run the addEmpByRequired method. 

3. The communication mechanism of the affairs of the Seventh Central Committee of the Communist Party of China

3.1, Propagation.REQUIRED (this is the default)

staff service

@Service
public class EmployeeServiceImpl implements EmployeeService {
 
    @Autowired
    EmployeeMapper employeeMapper;
 
    @Autowired
    DepartmentService departmentService;
 
    /**
     * 添加员工的同时添加部门
     * REQUIRED 传播
     * @param name 员工姓名
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addEmpByRequired(String name) {
        Employee employee = new Employee();
        employee.setDeptId(1);
        employee.setName(name);
        employee.setAddress("邯郸");
        employeeMapper.insertSelective(employee);
        departmentService.addDept("jishubu");
        int i = 1/0;
    }
}

 department service

@Service
public class DepartmentServiceImpl implements DepartmentService {
 
    @Autowired
    DepartmentMapper departmentMapper;
 
    @Override
    public void addDeptByRequired(String name) {
        Department department = new Department();
        department.setName(name);
        departmentMapper.insertSelective(department);
        // int i = 1/0;
    }
}
  • In the above code, no matter where the int i = 1/0 exception occurs, adding employees and adding departments will be rolled back. Because REQUIRED makes adding an employee and adding a department a transaction.
  • If you add @Transactional(propagation = Propagation.REQUIRED) on addDeptByRequired and do not add a transaction to addEmpByRequired, then addDeptByRequired is a transaction, and addEmpByRequired is not a transaction. Because addDeptByRequired starts a transaction, but addEmpByRequired does not exist in a transaction.

3.2、Propagation.SUPPORTS

staff service

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addEmpBySupports(String name) {
        Employee employee = new Employee();
        employee.setDeptId(2);
        employee.setName(name);
        employee.setAddress("邯郸");
        employeeMapper.insertSelective(employee);
        departmentService.addDeptBySupports("jishubu");
        // int i = 1/0;
    }

 department service

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public void addDeptBySupports(String name) {
        Department department = new Department();
        department.setName(name);
        departmentMapper.insertSelective(department);
        int i = 1/0;
    }
  • Regarding this attribute, in the above code, it is mainly added to addDeptBySupports, that is, the called method. Because adding to addEmpBySupports does not run in a transactional manner.
  • Then, if addEmpBySupports is transactional, addDeptBySupports is also transactional. If addEmpBySupports is not a transaction, addDeptBySupports is not a transaction either.

3.3、Propagation.MANDATORY 

staff service

    @Override
    // @Transactional(propagation = Propagation.REQUIRED)
    public void addEmpByMandatory(String name) {
        System.out.println("aaaaaa");
        Employee employee = new Employee();
        employee.setDeptId(3);
        employee.setName(name);
        employee.setAddress("邯郸");
        employeeMapper.insertSelective(employee);
        departmentService.addDeptByMandatory("jishubu");
        int i = 1/0;
    }

department service

    @Override
    @Transactional(propagation = Propagation.MANDATORY)
    public void addDeptByMandatory(String name) {
        Department department = new Department();
        department.setName(name);
        departmentMapper.insertSelective(department);
        int i = 1/0;
    }
  • This attribute is also added to addDeptByMandatory (callee). If added to addEmpByMandatory (caller), an exception will be thrown directly.
  • This attribute is added to addDeptByMandatory. If addEmpByMandatory has a transaction, addDeptByMandatory will be added to the transaction of addEmpByMandatory. If addEmpByMandatory has no transaction, an exception will be thrown directly.

3.4、Propagation.REQUIRES_NEW 

staff service

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addEmpByRequiresNew(String name) {
        Employee employee = new Employee();
        employee.setDeptId(4);
        employee.setName(name);
        employee.setAddress("邯郸");
        employeeMapper.insertSelective(employee);
        departmentService.addDeptByRequiresNew("jishubu");
        int i = 1/0;
    }

department service

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addDeptByRequiresNew(String name) {
        Department department = new Department();
        department.setName(name);
        departmentMapper.insertSelective(department);
        // int i = 1/0;
    }
  • This attribute should be the most used except REQUIRED. This property is also specific to the callee (addDeptByRequiresNew).
  • Regardless of whether the caller (addEmpByRequiresNew) has a transaction, the callee (addDeptByRequiresNew) will open a new transaction, which means that the callee exists in its own transaction and has nothing to do with the caller.
  • As in the above code, addEmpByRequiresNew will roll back, but addDeptByRequiresNew will not roll back. Because they are two transactions.

3.5、 Propagation.NOT_SUPPORTED

staff service

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addEmpByNotSupported(String name) {
        Employee employee = new Employee();
        employee.setDeptId(5);
        employee.setName(name);
        employee.setAddress("邯郸");
        employeeMapper.insertSelective(employee);
        departmentService.addDeptByNotSupported("jishubu");
        int i = 1/0;
    }

 department service

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void addDeptByNotSupported(String name) {
        Department department = new Department();
        department.setName(name);
        departmentMapper.insertSelective(department);
        int i = 1/0;
    }
  • If this attribute is placed on the caller (addEmpByNotSupported), it will run in a non-transactional manner.
  • If placed on the callee (addDeptByNotSupported), the method (addDeptByNotSupported) runs with a non-transaction, and the caller runs a separate transaction (pending) if it has one.
  • In the above code, there will be a rollback for adding employees, but no rollback for adding departments.

3.6、Propagation.NEVER 

staff service

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addEmpByNever(String name) {
        Employee employee = new Employee();
        employee.setDeptId(6);
        employee.setName(name);
        employee.setAddress("邯郸");
        employeeMapper.insertSelective(employee);
        departmentService.addDeptByNever("jishubu");
        int i = 1/0;
    }

department service

    @Override
    @Transactional(propagation = Propagation.NEVER)
    public void addDeptByNever(String name) {
        Department department = new Department();
        department.setName(name);
        departmentMapper.insertSelective(department);
        int i = 1/0;
    }
  • This property runs non-transactionally directly if on the caller. If it acts on the callee, it depends on whether the caller has a transaction. If the caller has a transaction, an exception is thrown. If there is no transaction, it runs as a non-transaction.
  • In the above code, an exception will be thrown. (It is not an exception except zero, but: Existing transaction found for transaction marked with propagation 'never')

3.7、Propagation.NESTED 

illustrate

A transaction started by PROPAGATION_NESTED is nested within an outer transaction (if one exists). Nested subtransactions are an application of JDBC's SavePoint, which is a single physical transaction with rollback to multiple savepoints. When the callee uses PROPAGATION_NESTED, JDBC 3.0 and above and JDK1.4 and above are required, and the implementer needs to support the savepoint transaction mechanism.

submit

Only through the submission of external transactions can the submission of internal transactions be caused. (Embedded transaction is not an independent transaction, it depends on external transaction)

rollback

When the parent transaction is rolled back, the child transaction must be rolled back.
The child transaction is rolled back to the savepoint, and the parent transaction can be selectively rolled back or not.

staff service 

    @Override
    @Transactional(propagation = Propagation.REQUIRED)     //1
    public void addEmpByNested(String name) {
        Employee employee = new Employee();
        employee.setDeptId(7);
        employeeMapper.insertSelective(employee);          //2
        try {
            departmentService.addDeptByNested("jishubu");  //3
        }catch (Exception e){
            // 其他业务, 如 departmentService.methodC();    //5
        }
        employee.setDeptId(8);
        employeeMapper.update(employee);                   //6
            // int i = 1/0;
    }

department service

    @Override
    @Transactional(propagation = Propagation.NESTED)
    public void addDeptByNested(String name) {
        Department department = new Department();
        department.setName(name);
        departmentMapper.insertSelective(department);  //4
        // int i = 1/0;
    }

1. A new transaction A will be opened

2. Insert data, transaction A is suspended without commit,

3. Create a new savepoint to save the data inserted in 2, without submitting it.

4. If addDeptByNested is abnormal, roll back the operation of 4 without affecting 2. At the same time, the logic of 5 and 6 behind can be processed, and the last commit together: 2, 5, 6, if addDeptByNested is normal, the last commit together: 2, 4, 6

If methodB uses PROPAGATION_REQUIRES_NEW, then B is abnormal and will commit: 2,5,6, which is consistent with NESTED.
If there is no abnormality in methodB, then commit4 will be committed first, and then commit:6, then the transaction will be separated and cannot be consistent. If an error is reported when executing 6, 2 and 6 will be rolled back, but 4 will not be rolled back, and the expected effect cannot be achieved .

NESTED is not the only one used for nesting, as long as you understand the meaning of the above seven propagation mechanisms, you can use it for nesting.

Original address:  Spring (SpringBoot)--Transaction Propagation Mechanism--Application/Instance/Detailed Explanation

Guess you like

Origin blog.csdn.net/m0_50370837/article/details/127145038