参考博客:Spring事务传播行为详解 - SegmentFault 思否
在Spring中,支持以下7中传播行为
事务传播行为类型 | 说明 |
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
PROPAGATION_REQUIRED
- 验证在未开启事务的方法中调用propagation = Propagation.REQUIRED的方法
@RequestMapping("/t/insert") // 测试没有开启事务,5、6都成功 public void test1() throws Exception { testService.insertWithoutTransaction(); } @RequestMapping("/t/insert/exception") // 测试没有开启事务,其中一个insert中由异常,7成功,8失败 public void test2() throws Exception { testService.insertWithoutTransactionException(); }
@Transactional(propagation = Propagation.REQUIRED) public void insert(User user) { userMapper.insert(user); } @Transactional(propagation = Propagation.REQUIRED) public void insertException(User user) throws Exception { userMapper.insert(user); throw new RuntimeException(); }
测试结果
- 测试在开启事务的方法中调用opagation = Propagation.REQUIRED的方法(常用)
开启事务后,opagation = Propagation.REQUIRED的方法会加入到这个事务中。
@RequestMapping("/t/insert/transaction") // 9、10都失败 public void test1() throws Exception { testService.insertTransactionThrowException(); } @RequestMapping("/t/insert/transaction/exception") // 11、12都失败 public void test2() throws Exception { testService.insertTransactionException(); } @RequestMapping("/t/insert/transaction/normal") // 13、14成功 public void test3() throws Exception { testService.insertTransactionNormal(); }
@Transactional public void insertTransactionThrowException() { User user = new User(9,"honghong","female"); userService.insert(user); User user1 = new User(10,"honghong","female"); userService.insert(user1); throw new RuntimeException(); } @Transactional public void insertTransactionException() { User user = new User(11,"honghong","female"); userService.insert(user); User user1 = new User(12,"honghong","female"); userService.insertException(user1); } @Transactional public void insertTransactionNormal() { User user = new User(13,"honghong","female"); userService.insert(user); User user1 = new User(14,"honghong","female"); userService.insert(user1); }
测试结果:
结论:以上试验结果我们证明在外围方法开启事务的情况下Propagation.REQUIRED修饰的内部方法会加入到外围方法的事务中,所有Propagation.REQUIRED修饰的内部方法和外围方法均属于同一事务,只要一个方法回滚,整个事务均回滚。
PROPAGATION_REQUIRES_NEW
- 场景1:外围方法未开启事务,被调用的方法传播行为为Propagation.REQUIRES_NEW。有两个方法,一个正常,一个抛异常。
@Transactional(propagation = Propagation.REQUIRES_NEW) public void insert(User user) { userMapper.insert(user); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void insertException(User user) { userMapper.insert(user); throw new RuntimeException(); }
public void insertTransactionNew() { User user = new User(11,"honghong","female"); userService.insert(user); User user1 = new User(12,"honghong","female"); userService.insertException(user1); }
测试结果:id为11的成功,id为12的失败
- 场景2:在insertTransactionNew方法上加上事务
测试结果:与场景1相同
PROPAGATION_NESTED
- 场景1,外围方法没加事务,被调用的方法加了propagation = Propagation.NESTED
由于外围方法没加事务,所以对于被调用方法来说就相当于Propagation.REQUIRED
@Transactional(propagation = Propagation.NESTED) public void insert(User user) { userMapper.insert(user); } @Transactional(propagation = Propagation.NESTED) public void insertException(User user) { userMapper.insert(user); throw new RuntimeException(); }
public void insertTransactionNested() { User user = new User(11,"honghong","female"); userService.insert(user); User user1 = new User(12,"honghong","female"); userService.insertException(user1); }
测试结果:id为11的入库成功
- 场景二:外围方法加上了事务,被调用的方法也加了propagation = Propagation.NESTED
@Transactional(propagation = Propagation.NESTED) public void insert(User user) { userMapper.insert(user); } @Transactional(propagation = Propagation.NESTED) public void insertException(User user) { userMapper.insert(user); throw new RuntimeException(); }
@Transactional public void insertTransactionNested() { User user = new User(11,"honghong","female"); userService.insert(user); User user1 = new User(12,"honghong","female"); userService.insertException(user1); }
- 测试结果:11和12都没有成功,因为NESTED是外围方法的子事务,插入12号的时候出现了异常,外围方法事务会回滚,所以子事务也会回滚。