实验七 事务属性:事务传播行为
1、引入事务传播行为
①Service方法应用了通知
②过滤器或拦截器等类似组件
2、事务传播行为要研究的问题
3、propagation属性
4、测试
①创建测试方法
[1]在EmpService中声明两个内层方法
[2]创建TopService
[3]junit测试方法
②测试 REQUIRED 模式
③测试 REQUIRES_NEW 模式
[1]修改 EmpService 中内层方法
[2]执行流程
实验七 事务属性:事务传播行为
1、引入事务传播行为
在大多数情况下,我们会认为事务操作要么都成功,要么回到初始状态。比如下订单,如果主订单添加成功,三个订单明细添加成功两个,总额就对不上了,顾客最终收货会有减少的。这种情况肯定要保证全部成功。类似还有银行转账例子。但也存在不同的需求,比如:
①Service方法应用了通知
②过滤器或拦截器等类似组件
2、事务传播行为要研究的问题
3、propagation属性
@Transactional 注解通过 propagation 属性设置事务的传播行为。propagation 属性的可选值由 org.springframework.transaction.annotation.Propagation 枚举类提供:
名称 | 含义 |
---|---|
REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是默认值。 |
REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
NESTED | 如当前存在事务,则在嵌套事务内执行。如当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作 |
4、测试
①创建测试方法
[1]在EmpService中声明两个内层方法
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void updateEmpNameInner(Integer empId, String empName) {
empDao.updateEmpNameById(empId, empName);<br />}
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void updateEmpSalaryInner(Integer empId, Double empSalary) {
empDao.updateEmpSalaryById(empId, empSalary);<br />}
[2]创建TopService
@Service
public class TopService {
// 这里我们只是为了测试事务传播行为,临时在Service中装配另一个Service<br /> // 实际开发时非常不建议这么做,因为这样会严重破坏项目的结构<br /> @Autowired<br /> private EmpService empService;
@Transactional<br /> public void topTxMethod() {
// 在外层方法中调用两个内层方法<br /> empService.updateEmpNameInner(2, "aaa");
empService.updateEmpSalaryInner(3, 666.66);<br /> }
}
[3]junit测试方法
@Autowired
private TopService topService;
@Test
public void testPropagation() {
// 调用外层方法<br /> topService.topTxMethod();
}
②测试 REQUIRED 模式
效果:内层方法A、内层方法B所做的修改都没有生效,总事务回滚了。
③测试 REQUIRES_NEW 模式
[1]修改 EmpService 中内层方法
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateEmpNameInner(Integer empId, String empName) {
empDao.updateEmpNameById(empId, empName);<br />}
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateEmpSalaryInner(Integer empId, Double empSalary) {
empDao.updateEmpSalaryById(empId, empSalary);<br />}
[2]执行流程
外层方法依次调用内层方法A,内层方法B,会挂起外层方法的事务,新开内层方法A的事务,内层方法B的事务。如果内层方法A执行成功,内层方法B执行出现异常,则内层方法B事务会回滚,外层方法事务也会回滚,但是内层方法A事务已经提交,不会回滚。