Spring传播机制(七种)

news/2025/2/19 15:43:25/

一、概述

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;}
}

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使用当前事务,没有事务,抛出异常

代码案例:

//controller
@RestController
@RequestMapping("/op")
public class TestController {@Autowiredprivate 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");}@Overridepublic 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 {@Autowiredprivate TestService2 testService2;@Overridepublic int insert(Test test) {return getBaseMapper().insert(test);}@Overridepublic 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 三者不同

参考文档: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();
@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();}}


http://www.ppmy.cn/news/87232.html

相关文章

组长给组员派活,把组长自己的需求和要改的bug派给组员,合理吗?

组长把自己的工作派给手下&#xff0c;合理吗&#xff1f; 一位程序员问&#xff1a; 组长给他派活&#xff0c;把组长自己的需求或者要改的bug派给他。组长分派完需求之后&#xff0c;他一个人干两个项目&#xff0c;组长却无所事事&#xff0c;这样合理吗&#xff1f; 有人说…

Day270/300 react hooks 使用useState 修改后,视图不更新

1、React 代码 {chatData.map(item > {return <div key{item.id}> </div>})}使用useState改变数组的值&#xff0c;dom没有更新&#xff1a; const showChat (item)>{item.open !item.openconsole.log(item-open,chatData)setChatData(chatData) }2、原因…

vector的介绍

vector的介绍&#xff1a;(vector翻译是向量&#xff0c;但是表示的是顺序表) vector是表示可以改变大小的数组的序列容器。 就像数组一样&#xff0c;vector对其元素使用连续的存储位置&#xff0c;这意味着也可以使用指向其元素的常规指针上的偏移量来访问它们的元素&#xf…

题解2023.5.21

B. Diverse Substrings 思路&#xff1a;直接枚举超时&#xff0c;数的种类为0-9&#xff0c;所以对于每个位置只需往后延伸100位即可&#xff0c;超过100位必重复 #include<bits/stdc.h> #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(fas…

Leetcode 1679. K 和数对的最大数目 双指针法

https://leetcode.cn/problems/max-number-of-k-sum-pairs/ 给你一个整数数组 nums 和一个整数 k 。 每一步操作中&#xff0c;你需要从数组中选出和为 k 的两个整数&#xff0c;并将它们移出数组。 返回你可以对数组执行的最大操作数。 示例 1&#xff1a; 输入&#xff1…

路由守卫

// 路由守卫 router.beforeEach((to, from,next) > { // 去哪里 console.log(to) // 从那来 console.log(from) // 继续执行的操作----next 不执行next哪里都进不去&#xff01;&#xff01;&#xff01; // next()-----网页正常跳转 // next(‘/’)–next中的参数是要跳转的…

Python对大量表格文件加以数据截取、逐行求差、跨文件合并等处理的方法

本文介绍基于Python语言&#xff0c;针对一个文件夹下大量的Excel表格文件&#xff0c;基于其中每一个文件&#xff0c;首先依据某一列数据的特征截取我们需要的数据&#xff0c;随后对截取出来的数据逐行求差&#xff0c;并基于其他多个文件夹中同样大量的Excel表格文件&#…

ChatGPT无限可能性:自然语言生成的奥秘

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; ChatGPT无限可能性&#xff1a;自然语言生成的奥秘 数字化时代&#xff1a;跨越语言和文化障碍 冰岛是北大西洋中部的一个岛国&#xff0c;拥有充满活力的科技产业和…