在我之前的教程中,Spring Boot事务管理例子中,我们了解了事务的声明式实现和管理。在这片文章中,我们会
来看事务的传播性以及不同的传播类型。下一篇文章中,我们将会学习Spring Boot 事务回滚和Spring Boot事务隔离级别。
事务的传播性是什么?
任何应用程序都涉及许多服务或组件,这些服务或组件需要调用其他服务或组件。事务传播指示任何组件或服务是否会参与或将参与事务,以及__如果调用组件/服务已经创建或尚未创建事务,它将如何执行__。

准备开始
我们将利用上一章已经开发好的Spring Boot事务项目。它已经具有Organization Service,该服务调用了Employee Service和Health Insurance Service。
并且,在之前的例子中,我们只是在Organization Service上添加了事务注解。
但是,假设用户希望同时调用Employee Service,即:
客户端通过Organization Service来调用Employee Service:

客户端直接调用Employee Service

因为可以直接调用Employee Service,我们将对Employee Service使用事务注解。所以,Employee Service和Organization Service都将使用事务注解。
我们将通过观察Employee Service和Organization Service的行为来观察各种传播场景。有六种类型的事务传播:
- REQUIRED
- SUPPORTS
- NOT_SUPPORTED
- REQUIRES_NEW
- NEVER
- MANDATORY
事务传播,默认是REQUIRED

左侧:如果insertEmployee()方法被直接调用,它会自己创建一个自己的新的事务。
右侧:如果insertEmployee()方法是从另外一个服务中调用的;
- 如果调用的service已经有一个事务,那么该方法就会使用已经存在的事务
- 如果调用的service中不存在事务,那么方法就会创建一个新的事务
所以如果存在事务,那么insertEmployee()方法就会继续使用原有的事务,否则就会利用REQUIRED来创建一个新的事务。
在这里,Organization Service和Employee Service都定义了事务的传播行为为Required这也是默认的事务传播行为,
代码:
下面是Organization Service的代码:
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;
@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {
@Autowired
EmployeeService employeeService;
@Autowired
HealthInsuranceService healthInsuranceService;
@Override
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.insertEmployee(employee);
if (employee.getEmpId().equals("emp1")) {
throw new RuntimeException("thowing exception to test transaction rollback");
}
healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
}
@Override
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.deleteEmployeeById(employee.getEmpId());
healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
}
}
Employee Service的代码如下所示:
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;
@Service
@Transactional
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeDao employeeDao;
@Override
public void insertEmployee(Employee employee) {
employeeDao.insertEmployee(employee);
}
@Override
public void deleteEmployeeById(String empid) {
employeeDao.deleteEmployeeById(empid);
}
}
输出
__通过使用OrganizationService__调用EmployeeService:

直接调用employeeService:

事务传播行为-SUPPORTS

从上图可以看出来两点
- 当
EmployeeService中方法insertEmployee()被直接调用的话,如果使用的事务传播行为为SUPPORTS,那么它不会自己创建自己新的事务 - 当
EmployeeService中insertEmployee()通过OrganizationService调用的时候,如果OrganizationService存在事务,那么insertEmployee就会沿用OrganizationService的事务传播行为,
否则如果OrganizationService不存在事务传播行为,那么insertEmployee()方法就会执行,但是不会开启任何事务。
在上面的示例中,OrganizationService的事务传播行为定义为REQUIRED,EmployeeService的事务定义为SUPPORTS
代码:
OrganizationService的实现如下:
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;
@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {
@Autowired
EmployeeService employeeService;
@Autowired
HealthInsuranceService healthInsuranceService;
@Override
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.insertEmployee(employee);
if (employee.getEmpId().equals("emp1")) {
throw new RuntimeException("thowing exception to test transaction rollback");
}
healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
}
@Override
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.deleteEmployeeById(employee.getEmpId());
healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
}
}
Employee Service的代码如下所示:
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;
@Service
@Transactional(propagation=Propagation.SUPPORTS)
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeDao employeeDao;
@Override
public void insertEmployee(Employee employee) {
employeeDao.insertEmployee(employee);
}
@Override
public void deleteEmployeeById(String empid) {
employeeDao.deleteEmployeeById(empid);
}
}
输出:

事务传播行为:NOT_SUPPORTED
![[外链图片转存失败(img-CpzTju2a-1566307900626)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_009.png)]](https://img-blog.csdnimg.cn/20190820213455928.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI5MzQzMjU=,size_16,color_FFFFFF,t_70)
从上面的描述中可以知道,当EmployeeService中insertEmployee被设定事务传播行为为NOT_SUPPORTED的时候, 直接调用该方法或者通过OrganizationService调用,该方法都不会创建事务或者沿用OrganizationService`的事务。
代码:
OrganizationService的实现如下:`
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;
@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {
@Autowired
EmployeeService employeeService;
@Autowired
HealthInsuranceService healthInsuranceService;
@Override
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.insertEmployee(employee);
if (employee.getEmpId().equals("emp1")) {
throw new RuntimeException("thowing exception to test transaction rollback");
}
healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
}
@Override
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.deleteEmployeeById(employee.getEmpId());
healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
}
}
EmployeeService的实现:
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;
@Service
@Transactional(propagation=Propagation.NOT_SUPPORTED)
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeDao employeeDao;
@Override
public void insertEmployee(Employee employee) {
employeeDao.insertEmployee(employee);
}
@Override
public void deleteEmployeeById(String empid) {
employeeDao.deleteEmployeeById(empid);
}
}
输出:

事务的传播行为REQUIRES_NEW
![[外链图片转存失败(img-scz5W9d9-1566307900629)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_011.png)]](https://img-blog.csdnimg.cn/20190820213523805.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI5MzQzMjU=,size_16,color_FFFFFF,t_70)
从图中的描述中可以知道,无论是直接被调用还是通过其他的Service来调用,事务的传播行为REQUIRES_NEW总是会创建自己的事务。
代码:
OrganizationService的实现如下:`
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;
@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {
@Autowired
EmployeeService employeeService;
@Autowired
HealthInsuranceService healthInsuranceService;
@Override
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.insertEmployee(employee);
if (employee.getEmpId().equals("emp1")) {
throw new RuntimeException("thowing exception to test transaction rollback");
}
healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
}
@Override
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.deleteEmployeeById(employee.getEmpId());
healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
}
}
EmployeeService的实现:
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;
@Service
@Transactional(propagation=Propagation.REQUIRES_NEW)
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeDao employeeDao;
@Override
public void insertEmployee(Employee employee) {
employeeDao.insertEmployee(employee);
}
@Override
public void deleteEmployeeById(String empid) {
employeeDao.deleteEmployeeById(empid);
}
}
输出:
![[外链图片转存失败(img-JY3oHdqE-1566307900630)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_012.png)]](https://img-blog.csdnimg.cn/20190820213540677.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI5MzQzMjU=,size_16,color_FFFFFF,t_70)
![[外链图片转存失败(img-1slkp2R0-1566307900631)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_013.png)]](https://img-blog.csdnimg.cn/20190820213551523.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI5MzQzMjU=,size_16,color_FFFFFF,t_70)
事务的传播行为:NEVER
![[外链图片转存失败(img-RmJGIdHY-1566307900632)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_014.png)]](https://img-blog.csdnimg.cn/20190820213619119.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI5MzQzMjU=,size_16,color_FFFFFF,t_70)
从上图可以知道,如果该方法直接被调用,它不会自己创建一个事务;如果该方法被其它的进行调用,如果调用的Service方法存在事务,那么就会抛出一个异常。
否则,它不会创建事务,然后自己运行。
代码:
OrganizationService的实现如下:`
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;
@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {
@Autowired
EmployeeService employeeService;
@Autowired
HealthInsuranceService healthInsuranceService;
@Override
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.insertEmployee(employee);
if (employee.getEmpId().equals("emp1")) {
throw new RuntimeException("thowing exception to test transaction rollback");
}
healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
}
@Override
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.deleteEmployeeById(employee.getEmpId());
healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
}
}
EmployeeService实现:
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;
@Service
@Transactional(propagation=Propagation.NEVER)
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeDao employeeDao;
@Override
public void insertEmployee(Employee employee) {
employeeDao.insertEmployee(employee);
}
@Override
public void deleteEmployeeById(String empid) {
employeeDao.deleteEmployeeById(empid);
}
}
输出:
![[外链图片转存失败(img-XwOPQdEb-1566307900633)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_015.png)]](https://img-blog.csdnimg.cn/20190820213633601.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI5MzQzMjU=,size_16,color_FFFFFF,t_70)
事务的传播行为:MANDATORY
![[外链图片转存失败(img-SNTbbJul-1566307900634)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_016.png)]](https://img-blog.csdnimg.cn/20190820213650256.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI5MzQzMjU=,size_16,color_FFFFFF,t_70)
如果方法上指定的事务传播行为为MANDATORY,直接被调用的时候会抛出异常;如果被其它服务调用,存在事务传播行为就会沿用,否则就会抛出异常。
代码:
OrganizationService的实现如下:`
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.model.Employee;
import com.javainuse.model.EmployeeHealthInsurance;
import com.javainuse.service.EmployeeService;
import com.javainuse.service.HealthInsuranceService;
import com.javainuse.service.OrganizationService;
@Service
@Transactional
public class OrganzationServiceImpl implements OrganizationService {
@Autowired
EmployeeService employeeService;
@Autowired
HealthInsuranceService healthInsuranceService;
@Override
public void joinOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.insertEmployee(employee);
if (employee.getEmpId().equals("emp1")) {
throw new RuntimeException("thowing exception to test transaction rollback");
}
healthInsuranceService.registerEmployeeHealthInsurance(employeeHealthInsurance);
}
@Override
public void leaveOrganization(Employee employee, EmployeeHealthInsurance employeeHealthInsurance) {
employeeService.deleteEmployeeById(employee.getEmpId());
healthInsuranceService.deleteEmployeeHealthInsuranceById(employeeHealthInsurance.getEmpId());
}
}
EmployeeService实现:
package com.javainuse.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;
@Service
@Transactional(propagation=Propagation.MANDATORY)
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeDao employeeDao;
@Override
public void insertEmployee(Employee employee) {
employeeDao.insertEmployee(employee);
}
@Override
public void deleteEmployeeById(String empid) {
employeeDao.deleteEmployeeById(empid);
}
}
输出:
![[外链图片转存失败(img-zfBk8eDD-1566307900635)(C:\Users\liyongyong\Desktop\spring_boot_transaction_propagation_017.png)]](https://img-blog.csdnimg.cn/20190820213703491.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTI5MzQzMjU=,size_16,color_FFFFFF,t_70)
事务传播行为总结
- REQUIRED :一直在事务中执行,如果这里存在事务,它会使用已经存在的事务;如果不存在事务,它会新建一个事务。
- SUPPORTS: 它可能在事务中运行,也可能不在事务中运行。如果当前事务存在,则支持它。如果不存在,则在没有事务的情况下执行。
- NOT_SUPPORTED : 始终在没有事务的情况下执行。如果存在现有事务,则挂起该事务。
- REQUIRES_NEW : 始终在新事务中执行。如果存在现有事务,则挂起该事务。
- NEVER : 在没有任何事务的情况下执行。如果存在现有事务,则引发异常
- MANDATORY :始终在事务中执行。如果存在现有事务,则使用该事务。如果没有现有事务,它将引发异常。
原文链接:https://dzone.com/articles/spring-boot-transactions-tutorial-understanding-tr
作者:Rida Shaikh
译者:lee
