Original website:
brief introduction
This paper introduces the transaction propagation mechanism in Spring, and illustrates its usage with an example.
This content is also a common question in Java back-end interview.
summary
Spring specifies seven types of transaction propagation behaviors in the TransactionDefinition interface. Propagation enumeration refers to these types. We generally use propagation enumeration directly in the development process. The three commonly used items have been bold.
Transaction propagation behavior type | explain |
PROPAGATION_REQUIRED | Transaction required (default). If there is no transaction at present, create a new transaction; If there is a current transaction, join it. |
PROPAGATION_SUPPORTS | Support transactions. If there is no transaction currently, it is executed in a non transactional manner. |
PROPAGATION_MANDATORY | Enforce the use of transactions. If there is a current transaction, use the current transaction; If there is no current transaction, an exception is thrown. |
PROPAGATION_REQUIRES_NEW | Create a new transaction. Create a new transaction run regardless of whether there is a transaction currently. |
PROPAGATION_NOT_SUPPORTED | Transaction is not supported. If there is a current transaction, suspend the current transaction and run the method. |
PROPAGATION_NEVER | Do not use transactions. If there is a transaction in the current method, an exception will be thrown; otherwise, the no transaction mechanism will continue to be used. |
PROPAGATION_NESTED | Nesting. If a transaction currently exists, it is executed within a nested transaction. If there is no current transaction, execute the same as the deployment_ Required similar operations. |
All the tests here are to run the addEmpByRequired method.
Propagation.REQUIRED
Employee service
@Service public class EmployeeServiceImpl implements EmployeeService { @Autowired EmployeeMapper employeeMapper; @Autowired DepartmentService departmentService; /** * Add department while adding employee * REQUIRED spread * @param name Employee name */ @Override @Transactional(propagation = Propagation.REQUIRED) public void addEmpByRequired(String name) { Employee employee = new Employee(); employee.setDeptId(1); employee.setName(name); employee.setAddress("Handan"); 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; } }
1. In the above code, no matter where the exception int i =1/0 occurs, adding employees and departments will be rolled back. Because REQUIRED will make adding employees and adding departments a transaction.
2. If @ Transactional(propagation = Propagation.REQUIRED) is added to addDeptByRequired and no transaction is added to addEmpByRequired, addDeptByRequired is a transaction and addEmpByRequired is not a transaction. Because addDeptByRequired starts a transaction, but addEmpByRequired does not exist in a transaction.
Propagation.SUPPORTS
Employee service
@Override @Transactional(propagation = Propagation.REQUIRED) public void addEmpBySupports(String name) { Employee employee = new Employee(); employee.setDeptId(2); employee.setName(name); employee.setAddress("Handan"); 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; }
- In the above code, this attribute is mainly added to addDeptBySupports, that is, the called method. Because it is added to addEmpBySupports, it will not run as a transaction.
- Then, if addEmpBySupports is a transaction, addDeptBySupports is also a transaction. If addEmpBySupports is not a transaction, addDeptBySupports is not a transaction.
Propagation.MANDATORY
Employee 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("Handan"); 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 it is added to addEmpByMandatory (caller), an exception is thrown directly.
- This attribute is added to adddeptbymandary. If there is a transaction in addEmpByMandatory, adddeptbymandary will be added to the transaction of addEmpByMandatory. If there is no transaction in addEmpByMandatory, an exception will be thrown directly.
Propagation.REQUIRES_NEW
Employee service
@Override @Transactional(propagation = Propagation.REQUIRES_NEW) public void addEmpByRequiresNew(String name) { Employee employee = new Employee(); employee.setDeptId(4); employee.setName(name); employee.setAddress("Handan"); 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 attribute is also for the callee (addDeptByRequiresNew).
- No matter whether the caller (addEmpByRequiresNew) has a transaction or not, 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 shown in the above code, addEmpByRequiresNew will roll back, but addDeptByRequiresNew will not roll back. Because they are two things.
Propagation.NOT_SUPPORTED
Employee service
@Override @Transactional(propagation = Propagation.REQUIRED) public void addEmpByNotSupported(String name) { Employee employee = new Employee(); employee.setDeptId(5); employee.setName(name); employee.setAddress("Handan"); 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 runs in a non transactional manner.
- If it is placed on the callee (addDeptByNotSupported), the method (addDeptByNotSupported) runs as a non transaction. If the caller has a transaction, it runs a separate transaction (suspended).
- In the above code, add employee rollback will appear, and add department will not rollback.
Propagation.NEVER
Employee service
@Override @Transactional(propagation = Propagation.REQUIRED) public void addEmpByNever(String name) { Employee employee = new Employee(); employee.setDeptId(6); employee.setName(name); employee.setAddress("Handan"); 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; }
- If this attribute is on the caller, it runs directly as a non transaction. 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. (not exception except 0, but: Existing transaction found for transaction marked with propagation 'never')
Propagation.NESTED
explain
PROPAGATION_ Transactions started by nested are embedded in external transactions, if any. Nested sub transaction is an application of JDBC SavePoint. It is a single physical transaction that can be rolled back to multiple savepoints. The callee uses propagation_ When nested, JDBC 3.0 and above and JDK1.4 and above are required, and the implementer needs to support the SavePoint transaction mechanism.
Submit
Internal transactions can only be committed through external transactions. (the embedded transaction is not an independent transaction, it depends on external transactions)
RollBACK
The parent transaction is rolled back, and 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 rolled back
Employee 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){ // Other businesses, such as departmentservice. Methodc()// five } 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. New service A will be started
2. Insert data. Transaction A is suspended without commit,
3. Create a savepoint to save 2 the inserted data without submitting.
4. If addDeptByNested is abnormal, roll back the operation of 4 without affecting 2. At the same time, the following 5,6 logic can be processed. The last commit: 2,5,6
If addDeptByNested has no exception, the last commit is: 2,4,6
Suppose methodB uses the PROPAGATION_REQUIRES_NEW, if B is abnormal, it will commit: 2,5,6, which is consistent with NESTED.
If there is no exception in methodB, commit 4 first and then commit:6, then the transaction will be separated and cannot be consistent. If an error is reported in execution 6, 2 and 6 will be rolled back, but 4 has not been rolled back, which cannot achieve the expected effect.
NESTED is not only used for nesting. As long as you understand the meaning of the above seven propagation mechanisms, they can be embedded and applied.
Other web sites
Spring transaction propagation mechanism - a drop in the sea - blog Park
Spring transaction propagation mechanism example - brief book
See also Spring Boot 2.x in simple terms = > 6.4 communication behavior