Spring中七种事务传播机制详解
作者:java-zh
这篇文章主要介绍了Spring中七种事务传播机制详解,Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,Propagation枚举则引用了这些类型,开发过程中我们一般直接用Propagation枚举,需要的朋友可以参考下
一、概述
Spring在TransactionDefinition接口中规定了7种类型的事务传播行为。
Propagation枚举则引用了这些类型,开发过程中我们一般直接用Propagation枚举。
1.1 Propagation源码
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; }}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; } }
1.2、类型解析
- Propagation.REQUIRED(默认机制):如果当前存在事务,那么就加入这个事务,不存在就新建一个事务。
- Propagation.SUPPORTS:如果当前有事务,加入事务,如果没有则不使用事务
- Propagation.MANDATORY:使用当前事务,如果当前没有事务,就抛出异常
- Propagation.REQUIRES_NEW:新建新的事务,如果当前存在事务,就把当前事务挂起
- Propagation.NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,把当前事务挂起
- Propagation.NEVER:以非事务方式执行操作,如果当前存在事务,就抛出异常
- Propagation.NESTED:如果当前存在事务,则嵌套在事务内执行。如果当前没有事务,则执行Propagation.REQUIRED类似操作
1.3 分类举例
传播机制 | 解释 |
Propagation.NEVER | 非事务执行操作,存在事务,抛出异常 |
Propagation.MANDATORY | 使用当前事务,没有事务,抛出异常 |
代码案例:
//controller @RestController @RequestMapping("/op") public class TestController { @Autowired private TestService testService; @GetMapping("/test1") public void test1() { testService.test1(); } } //service public interface TestService2 extends BaseService<Test> { void test2(); void test3(); } @Service public class TestServiceImpl2 extends BaseServiceImpl<TestMapper, Test> implements TestService2 { @Override @Transactional(propagation = Propagation.NEVER, rollbackFor = Exception.class) public void test2() { System.out.println("test2 存在事务 NEVER"); } @Override public void test3() { System.out.println("test3 没有事务"); } } public interface TestService extends BaseService<Test> { int insert(Test test); int update(Test test); void test1(); void test4(); } @Service public class TestServiceImpl extends BaseServiceImpl<TestMapper, Test> implements TestService { @Autowired private TestService2 testService2; @Override public int insert(Test test) { return getBaseMapper().insert(test); } @Override public int update(Test test) { return getBaseMapper().updateById(test); } @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void test1() { System.out.println("test1 存在事务 REQUIRED"); //如果在调用NEVER类型的时候,一定要用这种代理的方式,NEVER才会生效 testService2.test2(); } @Override @Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class) public void test4() { System.out.println("test4 存在事务 MANDATORY"); testService2.test3(); } }
测试结果
Propagation.NEVER
Propagation.MANDATORY
传播机制 | 解释 |
Propagation.REQUIRED | 需要在事务中执行,外层有事务就加入,没有事务就自己创建一个事务 |
Propagation.REQUIRES_NEW | 需要在一个新的事务中执行,这个事务独立于外层的事务,互不影响 |
Propagation.REQUIRES_NEW案例
@Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void test5() { System.out.println("当前事务 REQUIRED "); Test test = new Test(); test.setUserName("上海"); test.setAddress("中国"); getBaseMapper().insert(test); //test6用REQUIRES_NEW修饰,里面有异常,那么当前的事务也会回滚,如果test5有异常,test6不会受到影响 testService2.test6(); //当前事务进行回滚,test6内容会正常增加 int i = 1/0; } @Override @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class) public void test6() { System.out.println("创建了一个新的事务"); Test test = new Test(); test.setUserName("广州"); test.setAddress("中国"); getBaseMapper().insert(test); }
注意点:
REQUIRES_NEW如果在内层,它里面的事务独立于外层的事务,外层事务如果发送异常回滚跟REQUIRES_NEW里面内容无关,如果REQUIRES_NEW里面内容回滚,那么外层的事务也会跟着回滚。
Propagation.REQUIRES_NEW测试结果
传播机制 | 解释 |
Propagation.SUPPORTS | 外层有事务就加入,如果没有事务,就以非事务方式执行 |
Propagation.NOT_SUPPORTED | 以非事务的方式执行,执行的时候,先将外层的事务挂起,允许外层有事务。 |
传播机制 | 解释 |
Propagation.NESTED | 嵌套事务,它是已经存在事务的真正子事务,嵌套事务开始执行时,会取得一个保存点(savepoint),如果这个嵌套事务失败,将会回滚导这个保存点(savepoint),而不是整个事务的回滚 |
@Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void test7() { System.out.println("当前事务 REQUIRED "); Test test = new Test(); test.setUserName("上海"); test.setAddress("中国"); getBaseMapper().insert(test); //NESTED事务如果进行回滚,但是不会对它外层的事务造成影响 try{ testService2.test8(); }catch (Exception e){ } } @Override @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class) public void test8() { System.out.println("创建了一个新的子事务"); Test test = new Test(); test.setUserName("广州"); test.setAddress("中国"); getBaseMapper().insert(test); int i = 1/0; }
二、总结
2.1 REQUIRED,REQUIRES_NEW,NESTED
状态 | REQUIRES_NEW(两个独立事务) | NESTED(B事务嵌套在A事务中) | REQUIRED同一个事务 |
A异常B正常 | A回滚,B正常提交 | A与B一起回滚 | A与B一起回滚 |
A正常B异常 | B先回滚,A正常提交 | B先回滚,A再正常提交 | A与B一起回滚 |
A正常B正常 | B先提交,A再提交 | A与B一起提交 | A与B一起提交 |
2.2 三者不同
REQUIRED
- 假设在A⽅法存在⼀个当前事务,B⽅法的事务传播机制为REQUIRED,则B⽅法会合并到A⽅法的事务⾥执⾏。
- A、B任意⼀个⽅法异常(默认是RuntimeException和Error)都会导致A、B的操作被回滚。
- Spring事务管理器不会吞异常。
- B异常后会抛给A,A如果没有catch这个异常,会继续向上抛。如果A catch住了,Spring事务管理器会替A向上抛⼀个
- UnexpectedRollbackException。总之,⼀旦A、B回滚,A的调⽤⽅⼀定能收到⼀个异常感知到回滚。(问题所在)
REQUIRES_NEW
- 如果B发⽣异常,B事务⼀定回滚,B的异常随后会抛给A,如果A catch住了这个异常,A不会回滚,否则A也会回滚。
- 如果A发⽣异常,则只会回滚A,不会回滚B。
NESTED
- 如果B异常,B⼀定回滚,B的异常随后会抛给A,如果A catch住了这个异常,A不会回滚,否则A也会回滚。这种情况和REQUIRES_NEW⼀样。
- 如果A发⽣异常,则A、B都会回滚。
2.3 手动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void test7() { System.out.println("当前事务 REQUIRED "); Test test = new Test(); test.setUserName("上海"); test.setAddress("中国"); getBaseMapper().insert(test); //NESTED事务如果进行回滚,但是不会对它外层的事务造成影响 try{ testService2.test8(); }catch (Exception e){ TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }
到此这篇关于Spring中七种事务传播机制详解的文章就介绍到这了,更多相关Spring事务传播机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!