事务分析(二) 事务传播
事务传播分析 @Transaction Propagation
一.源码中的7种事务传播类型
public enum Propagation { REQUIRED(0), SUPPORTS(1), MANDATORY(2), REQUIRES_NEW(3), NOT_SUPPORTED(4), NEVER(5), NESTED(6); private final int value; private Propagation(int value) { this.value = value; } public int value() { return this.value; } }
7种事务的翻译:
事务传播类型 |
英文注释 |
中文翻译 |
REQUIRED
|
/** |
支持当前事务,如果不存在则创建新事务 PS:这是事务注解(@Transactional)的默认设置 |
SUPPORTS |
/** |
支持当前事务,如果不存在,则非事务性执行 |
MANDATORY |
/** |
支持当前事务,如果不存在事务,则引发异常 |
REQUIRES_NEW |
/** |
创建一个新事务,如果当前事务存在,则挂起当前事务 |
NOT_SUPPORTED |
/** |
非事务性执行,如果当前事务存在,则挂起当前事务 |
NEVER |
/** |
以非事务方式执行,如果事务存在,则抛出异常 |
NESTED |
/** |
如果当前事务存在,则在嵌套事务中执行 |
二.事务传播类型分析
1.REQUIRED 支持当前事务,如果不存在则创建新事务
//场景1 public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); } @Transactional(propagation = Propagation.REQUIRED) public void propagation2(){ userMapper.insert("老钱",84); System.err.println(1/0); }
//场景2 @Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); } @Transactional(propagation = Propagation.REQUIRED) public void propagation2(){ userMapper.insert("老钱",84); System.err.println(1/0); }
//场景3 @Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); System.err.println(1/0); } @Transactional(propagation = Propagation.REQUIRED) public void propagation2(){ userMapper.insert("老钱",84); }
方法名称 | propagation1 | propagation2 | 结果 |
事务配置场景1 | 无事务 |
异常放到propagation2:System.err.println(1/0); @Transactional(propagation = Propagation.REQUIRED) |
小李录入数据库成功 老钱录入数据库失败 |
事务配置场景2 |
@Transactional(propagation = Propagation.REQUIRED) |
异常放到propagation2:System.err.println(1/0); @Transactional(propagation = Propagation.REQUIRED) |
小李录入数据库失败 老钱录入数据库失败 |
事务配置场景3 |
异常放到propagation1:System.err.println(1/0); @Transactional(propagation = Propagation.REQUIRED) |
@Transactional(propagation = Propagation.REQUIRED) |
小李录入数据库失败 老钱录入数据库失败 |
小结:子事务是 REQUIRED 时,父方法存在事务则加入父事务,回滚服从父事务的执行情况.
2.SUPPORTS 支持当前事务,如果不存在,则非事务性执行
方法名称 | propagation1 | propagation2 | 结果 |
事务配置场景1 | 无事务 |
异常放到propagation2:System.err.println(1/0) @Transactional(propagation = Propagation.SUPPORTS) |
小李录入数据库成功 老钱录入数据库成功 |
事务配置场景2 |
@Transactional(propagation = Propagation.REQUIRED) |
异常放到propagation2:System.err.println(1/0) @Transactional(propagation = Propagation.SUPPORTS) |
小李录入数据库失败 老钱录入数据库失败 |
3.MANDATORY 支持当前事务,如果不存在事务,则引发异常
//场景1 @Service public class TestPropagationService1 { @Autowired UserMapper userMapper; @Autowired TestPropagationService2 service2; //@Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); } } @Service public class TestPropagationService2 { @Autowired UserMapper userMapper; @Transactional(propagation = Propagation.MANDATORY ) public void propagation2(){ userMapper.insert("老钱",84); System.err.println(1/0); } }
//场景2 @Service public class TestPropagationService1 { @Autowired UserMapper userMapper; @Autowired TestPropagationService2 service2; @Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); } } @Service public class TestPropagationService2 { @Autowired UserMapper userMapper; @Transactional(propagation = Propagation.MANDATORY ) public void propagation2(){ userMapper.insert("老钱",84); System.err.println(1/0); } }
方法名称 | propagation1 | propagation2 | 结果 |
事务配置场景1 | 无事务 |
@Transactional(propagation = Propagation.MANDATORY) |
小李录入数据库成功 老钱录入数据库失败 |
事务配置场景2 |
@Transactional(propagation = Propagation.REQUIRED) |
异常放到propagation2:System.err.println(1/0) @Transactional(propagation = Propagation.MANDATORY) |
小李录入数据库失败 老钱录入数据库失败 |
4.REQUIRES_NEW 创建一个新事务,如果当前事务存在,则挂起当前事务
//场景1 //@Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void propagation2(){ userMapper.insert("老钱",84); System.err.println(1/0); }
//场景2 @Autowired UserMapper userMapper; @Autowired TestPropagationService2 service2; @Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void propagation2(){ userMapper.insert("老钱",84); System.err.println(1/0); }
//场景3 @Autowired UserMapper userMapper; @Autowired TestPropagationService2 service2; @Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); System.err.println(1/0); } @Autowired UserMapper userMapper; @Transactional(propagation = Propagation.REQUIRES_NEW) public void propagation2(){ userMapper.insert("老钱",84); }
方法名称 | propagation1 | propagation2 | 结果 |
事务配置场景1 | 无事务 |
异常放到propagation2:System.err.println(1/0) @Transactional(propagation = Propagation.REQUIRES_NEW) |
小李录入数据库成功 老钱录入数据库失败 |
事务配置场景2 |
@Transactional(propagation = Propagation.REQUIRED) |
异常放到propagation2:System.err.println(1/0) @Transactional(propagation = Propagation.REQUIRES_NEW) |
小李录入数据库失败 老钱录入数据库失败 |
事务配置场景3 |
异常放到propagation1 System.err.println(1/0) @Transactional(propagation = Propagation.REQUIRED) |
@Transactional(propagation = Propagation.REQUIRES_NEW) |
小李录入数据库失败 老钱录入数据库成功 |
5.NOT_SUPPORTED 非事务性执行,如果当前事务存在,则挂起当前事务
方法名称 | propagation1 | propagation2 | 结果 |
事务配置场景1 |
@Transactional(propagation = Propagation.REQUIRED) |
异常放到propagation2:System.err.println(1/0); @Transactional(propagation = Propagation.NOT_SUPPORTED) |
小李录入数据库失败 老钱录入数据库成功 |
事务配置场景2 |
异常放到propagation1:System.err.println(1/0) @Transactional(propagation = Propagation.REQUIRED) |
@Transactional(propagation = Propagation.NOT_SUPPORTED) |
小李录入数据库失败 老钱录入数据库成功 |
//场景1 @Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); } @Transactional(propagation = Propagation.NOT_SUPPORTED) public void propagation2(){ userMapper.insert("老钱",84); System.err.println(1/0); }
//场景2 @Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); System.err.println(1/0); } @Transactional(propagation = Propagation.NOT_SUPPORTED) public void propagation2(){ userMapper.insert("老钱",84); }
6.NEVER 以非事务方式执行,如果事务存在,则抛出异常
方法名称 | propagation1 | propagation2 | 结果 |
事务配置场景1 | 无事务 |
异常放到propagation2:System.err.println(1/0); @Transactional(propagation = Propagation.NEVER) |
小李录入数据库成功 老钱录入数据库成功 |
事务配置场景2 |
@Transactional(propagation = Propagation.REQUIRED) |
@Transactional(propagation = Propagation.NEVER) |
小李录入数据库失败 老钱录入数据库失败 |
场景2会抛出异常: org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'
//场景1 public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); } @Transactional(propagation = Propagation.NEVER) public void propagation2(){ userMapper.insert("老钱",84); System.err.println(1/0); }
//场景2 @Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); } @Transactional(propagation = Propagation.NEVER) public void propagation2(){ userMapper.insert("老钱",84); //System.err.println(1/0); }
7.NESTED 如果当前事务存在,则在嵌套事务中执行
//场景1 @Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); } @Transactional(propagation = Propagation.NESTED) public void propagation2(){ userMapper.insert("老钱",84); System.err.println(1/0); }
//场景2 @Transactional(propagation = Propagation.REQUIRED) public void propagation1(){ userMapper.insert("小李",44); service2.propagation2(); System.err.println(1/0); } @Transactional(propagation = Propagation.NESTED) public void propagation2(){ userMapper.insert("老钱",84); }
方法名称 | propagation1 | propagation2 | 结果 |
事务配置场景1 |
@Transactional(propagation = Propagation.REQUIRED) |
异常放到propagation2:System.err.println(1/0); @Transactional(propagation = Propagation.NESTED) |
小李录入数据库失败 老钱录入数据库失败 |
事务配置场景2 |
异常放到propagation1:System.err.println(1/0); @Transactional(propagation = Propagation.REQUIRED) |
@Transactional(propagation = Propagation.NESTED) |
小李录入数据库失败 老钱录入数据库失败 |
小结:
嵌套事务:参考文章 https://blog.csdn.net/javashareauthor/article/details/82842177
什么是嵌套事务? 嵌套是子事务在父事务中执行,子事务是父事务的一部分,在进入子事务之前,父事务建立一个回滚点,叫save point,然后执行子事务,这个子事务的执行也算是父事务的一部分,然后子事务执行结束,父事务继续执行。 可以通过下述的问答进一步去熟悉嵌套事务? 1)如果子事务回滚,会发生什么? 父事务会回滚到进入子事务前建立的save point,然后尝试其他的事务或者其他的业务逻辑,父事务之前的操作不会受到影响,更不会自动回滚。 2)如果父事务回滚,会发生什么? 父事务回滚,子事务也会跟着回滚!为什么呢,因为父事务结束之前,子事务是不会提交的,我们说子事务是父事务的一部分,正是这个道理。 3)事务的提交,是什么情况? 父事务先提交,然后子事务提交,还是子事务先提交,父事务再提交?答案是第二种情况,还是那句话,子事务是父事务的一部分,由父事务统一提交