当前位置:   article > 正文

Spring传播机制(七种)_spring事务传播机制

spring事务传播机制

一、概述

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为。Propagation枚举则引用了这些类型,开发过程中我们一般直接用Propagation枚举。

1.1 Propagation源码

  1. public enum Propagation {
  2. REQUIRED(0),
  3. SUPPORTS(1),
  4. MANDATORY(2),
  5. REQUIRES_NEW(3),
  6. NOT_SUPPORTED(4),
  7. NEVER(5),
  8. NESTED(6);
  9. private final int value;
  10. private Propagation(int value) {
  11. this.value = value;
  12. }
  13. public int value() {
  14. return this.value;
  15. }
  16. }

1.2、类型解析

  • Propagation.REQUIRED(默认机制):如果当前存在事务,那么就加入这个事务,不存在就新建一个事务。
  • Propagation.SUPPORTS:如果当前有事务,加入事务,如果没有则不使用事务
  • Propagation.MANDATORY:使用当前事务,如果当前没有事务,就抛出异常
  • Propagation.REQUIRES_NEW:新建新的事务,如果当前存在事务,就把当前事务挂起
  • Propagation.NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,把当前事务挂起
  • Propagation.NEVER:以非事务方式执行操作,如果当前存在事务,就抛出异常
  • Propagation.NESTED:如果当前存在事务,则嵌套在事务内执行。如果当前没有事务,则执行Propagation.REQUIRED类似操作。

1.3 分类举例

参考文档:Spring事务管理中的七种传播机制及示例讲解 | 程序员小羊

传播机制解释
Propagation.NEVER非事务执行操作,存在事务,抛出异常
Propagation.MANDATORY使用当前事务,没有事务,抛出异常

代码案例:

  1. //controller
  2. @RestController
  3. @RequestMapping("/op")
  4. public class TestController {
  5. @Autowired
  6. private TestService testService;
  7. @GetMapping("/test1")
  8. public void test1() {
  9. testService.test1();
  10. }
  11. }
  12. //service
  13. public interface TestService2 extends BaseService<Test> {
  14. void test2();
  15. void test3();
  16. }
  17. @Service
  18. public class TestServiceImpl2 extends BaseServiceImpl<TestMapper, Test> implements TestService2 {
  19. @Override
  20. @Transactional(propagation = Propagation.NEVER, rollbackFor = Exception.class)
  21. public void test2() {
  22. System.out.println("test2 存在事务 NEVER");
  23. }
  24. @Override
  25. public void test3() {
  26. System.out.println("test3 没有事务");
  27. }
  28. }
  29. public interface TestService extends BaseService<Test> {
  30. int insert(Test test);
  31. int update(Test test);
  32. void test1();
  33. void test4();
  34. }
  35. @Service
  36. public class TestServiceImpl extends BaseServiceImpl<TestMapper, Test> implements TestService {
  37. @Autowired
  38. private TestService2 testService2;
  39. @Override
  40. public int insert(Test test) {
  41. return getBaseMapper().insert(test);
  42. }
  43. @Override
  44. public int update(Test test) {
  45. return getBaseMapper().updateById(test);
  46. }
  47. @Override
  48. @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  49. public void test1() {
  50. System.out.println("test1 存在事务 REQUIRED");
  51. //如果在调用NEVER类型的时候,一定要用这种代理的方式,NEVER才会生效
  52. testService2.test2();
  53. }
  54. @Override
  55. @Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)
  56. public void test4() {
  57. System.out.println("test4 存在事务 MANDATORY");
  58. testService2.test3();
  59. }
  60. }

测试结果

Propagation.NEVER

Propagation.MANDATORY

传播机制解释
Propagation.REQUIRED需要在事务中执行,外层有事务就加入,没有事务就自己创建一个事务
Propagation.REQUIRES_NEW需要在一个新的事务中执行,这个事务独立于外层的事务,互不影响

Propagation.REQUIRES_NEW案例

  1. @Override
  2. @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  3. public void test5() {
  4. System.out.println("当前事务 REQUIRED ");
  5. Test test = new Test();
  6. test.setUserName("上海");
  7. test.setAddress("中国");
  8. getBaseMapper().insert(test);
  9. //test6用REQUIRES_NEW修饰,里面有异常,那么当前的事务也会回滚,如果test5有异常,test6不会受到影响
  10. testService2.test6();
  11. //当前事务进行回滚,test6内容会正常增加
  12. int i = 1/0;
  13. }
  14. @Override
  15. @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
  16. public void test6() {
  17. System.out.println("创建了一个新的事务");
  18. Test test = new Test();
  19. test.setUserName("广州");
  20. test.setAddress("中国");
  21. getBaseMapper().insert(test);
  22. }

注意点:

REQUIRES_NEW如果在内层,它里面的事务独立于外层的事务,外层事务如果发送异常回滚跟REQUIRES_NEW里面内容无关,如果REQUIRES_NEW里面内容回滚,那么外层的事务也会跟着回滚。

Propagation.REQUIRES_NEW测试结果

传播机制解释
Propagation.SUPPORTS外层有事务就加入,如果没有事务,就以非事务方式执行
Propagation.NOT_SUPPORTED以非事务的方式执行,执行的时候,先将外层的事务挂起,允许外层有事务。

传播机制解释
Propagation.NESTED        嵌套事务,它是已经存在事务的真正子事务,嵌套事务开始执行时,会取得一个保存点(savepoint),如果这个嵌套事务失败,将会回滚导这个保存点(savepoint),而不是整个事务的回滚

  1. @Override
  2. @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  3. public void test7() {
  4. System.out.println("当前事务 REQUIRED ");
  5. Test test = new Test();
  6. test.setUserName("上海");
  7. test.setAddress("中国");
  8. getBaseMapper().insert(test);
  9. //NESTED事务如果进行回滚,但是不会对它外层的事务造成影响
  10. try{
  11. testService2.test8();
  12. }catch (Exception e){
  13. }
  14. }
  15. @Override
  16. @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
  17. public void test8() {
  18. System.out.println("创建了一个新的子事务");
  19. Test test = new Test();
  20. test.setUserName("广州");
  21. test.setAddress("中国");
  22. getBaseMapper().insert(test);
  23. int i = 1/0;
  24. }

二、总结

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 三者不同

参考文档:Spring嵌套事务异常Transaction rolled back because it has been marked as rollback-only_spring事务嵌套异常处理_Black·Tea的博客-CSDN博客

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();
  1. @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  2. public void test7() {
  3. System.out.println("当前事务 REQUIRED ");
  4. Test test = new Test();
  5. test.setUserName("上海");
  6. test.setAddress("中国");
  7. getBaseMapper().insert(test);
  8. //NESTED事务如果进行回滚,但是不会对它外层的事务造成影响
  9. try{
  10. testService2.test8();
  11. }catch (Exception e){
  12. TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  13. }
  14. }

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号