在我之前的教程中,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
从上面的描述中可以知道,当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
从图中的描述中可以知道,无论是直接被调用还是通过其他的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);
}
}
输出:
事务的传播行为:NEVER
从上图可以知道,如果该方法直接被调用,它不会自己创建一个事务;如果该方法被其它的进行调用,如果调用的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);
}
}
输出:
事务的传播行为:MANDATORY
如果方法上指定的事务传播行为为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);
}
}
输出:
事务传播行为总结
- REQUIRED :一直在事务中执行,如果这里存在事务,它会使用已经存在的事务;如果不存在事务,它会新建一个事务。
- SUPPORTS: 它可能在事务中运行,也可能不在事务中运行。如果当前事务存在,则支持它。如果不存在,则在没有事务的情况下执行。
- NOT_SUPPORTED : 始终在没有事务的情况下执行。如果存在现有事务,则挂起该事务。
- REQUIRES_NEW : 始终在新事务中执行。如果存在现有事务,则挂起该事务。
- NEVER : 在没有任何事务的情况下执行。如果存在现有事务,则引发异常
- MANDATORY :始终在事务中执行。如果存在现有事务,则使用该事务。如果没有现有事务,它将引发异常。
原文链接:https://dzone.com/articles/spring-boot-transactions-tutorial-understanding-tr
作者:Rida Shaikh
译者:lee