当前位置: 首页 > news >正文

关于Spring @Transactional事务传播机制详解

  • Spring事务传播机制
    • 1.什么是事务传播机制?
    • 2.Spring事务传播类型Propagation介绍
    • 3.具体案例
  • 总结

Spring事务传播机制

1.什么是事务传播机制?

举个栗子,方法A是一个事务的方法,方法A执行过程中调用了方法B,那么方法B有无事务以及方法B对事务的要求不同都会对方法A的事务具体执行造成影响,同时方法A的事务对方法B的事务执行也有影响,这种影响具体是什么就由两个方法所定义的事务传播类型所决定。

简单说就是,我们方法调用通常是,一个方法调用另外一个,而不同方法可以有不同的事务,所以传播机制就是指在多个方法,事务要如何传播。

2.Spring事务传播类型Propagation介绍

一共有七种传播类型

  • Propagation.REQUIRED
  • Propagation.SUPPORTS
  • Propagation.MANDATORY
  • Propagation.REQUIRED_NEW
  • Propagation.NOT_SUPPORTED
  • Propagation.NESTED
  • Propagation.NEVER

本文从案例结合解释一下不同传播类型下多个@Transactional方法会发生什么?在遇到异常情况下,不同传播机制会产生什么影响。

1. Propagation.REQUIRED

这是默认的传播机制,我们最常用的一种,也是@Transactional默认的一种

如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务

1

2

3

4

5

6

7

8

9

10

11

12

// 示例1:

@Transactional(propagation = Propagation.REQUIRED)

public void main(){

    insertA();  // 插入A

    service.sub();   // 调用其他方法

}

// 两个Service中调用,如果同一个要注意不能用this调用,事务不会起作用

@Transactional(propagation = Propagation.REQUIRED)

public void sub(){

    insertB();  //插入B

    throw RuntimeException;     //发生异常抛出

    insertC();  //调用C

简单来说就是,开启一个事务,上面的案例就是当main方法如果没开启事务,那么sub方法就会开启,如果main方法已经@Transactional开启了事务,sub方法就会加入外层方法的事务,所以上面方法执行在遇到异常时候会全部回滚

结果:

A、B、C全部无法插入。

1

2

3

4

5

6

7

8

9

10

11

// 示例2:

public void main(){

    insertA();  // 插入A

    service.sub();   // 调用其他方法

}

// 两个Service中调用,如果同一个要注意不能用this调用,事务不会起作用

@Transactional(propagation = Propagation.REQUIRED)

public void sub(){

    insertB();  //插入B

    throw RuntimeException;     //发生异常抛出

    insertC();  //调用C

结果:

A插入成功,BC开启新的事务,遇到异常回滚,B、C无法插入

2. Propagation.SUPPORTS

当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行

1

2

3

4

5

6

7

8

9

10

11

// 示例3:

public void main(){

    insertA();  // 插入A

    service.sub();   // 调用其他方法

}

// 两个Service中调用,如果同一个要注意不能用this调用,事务不会起作用

@Transactional(propagation = Propagation.SUPPORTS)

public void sub(){

    insertB();  //插入B

    throw RuntimeException;     //发生异常抛出

    insertC();  //调用C

这个和REQUIRED很像,但是里层的sub方法事务取决于main方法,如果main方法有开启那么里面的就和外层事务一起,如果发生异常全部回滚。

结果:

A、B插入成功,C无法插入因为发生异常

3. Propagation.MANDATORY

当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。

1

2

3

4

5

6

7

8

9

10

11

// 示例4:

public void main(){

    insertA();  // 插入A

    service.sub();   // 调用其他方法

}

// 两个Service中调用,如果同一个要注意不能用this调用,事务不会起作用

@Transactional(propagation = Propagation.MANDATORY)

public void sub(){

    insertB();  //插入B

    throw RuntimeException;     //发生异常抛出

    insertC();  //调用C

这种情形的执行结果就是insertA存储成功,而insertB和insertC没有存储。b和c没有存储,并不是事务回滚的原因,而是因为main方法没有声明事务,在去执行sub方法时就直接抛出事务要求的异常(如果当前事务不存在,则抛出异常),所以sub方法里的内容就完全没有执行。

结果:

A插入成功,B、C无法插入,方法抛出异常

那么当main方法有事务的情况下

1

2

3

4

5

6

7

8

9

10

11

12

// 示例5:

@Transactional(propagation = Propagation.REQUIRED)

public void main(){

    insertA();  // 插入A

    service.sub();   // 调用其他方法

}

// 两个Service中调用,如果同一个要注意不能用this调用,事务不会起作用

@Transactional(propagation = Propagation.MANDATORY)

public void sub(){

    insertB();  //插入B

    throw RuntimeException;     //发生异常抛出

    insertC();  //调用C

结果:

A、B、C全部无法插入,A、B回滚

4. Propagation.REQUIRED_NEW

创建一个新事务,如果存在当前事务,则挂起该事务。

1

2

3

4

5

6

7

8

9

10

11

12

// 示例5:

@Transactional(propagation = Propagation.REQUIRED)

public void main(){

    insertA();  // 插入A

    service.sub();   // 调用其他方法

    throw RuntimeException;     //发生异常抛出

}

// 两个Service中调用,如果同一个要注意不能用this调用,事务不会起作用

@Transactional(propagation = Propagation.REQUIRES_NEW)

public void sub(){

    insertB();  //插入B

    insertC();  //调用C

因为sub方法会开启一个新的事务,所以main方法抛出的异常并不会影响sub方法的提交

结果:

A插入失败,B、C能插入成功

5. Propagation.NOT_SUPPORTED

始终以非事务方式执行,如果当前存在事务,则挂起当前事务

1

2

3

4

5

6

7

8

9

10

11

12

// 示例6:

@Transactional(propagation = Propagation.REQUIRED)

public void main(){

    insertA();  // 插入A

    service.sub();   // 调用其他方法

}

// 两个Service中调用,如果同一个要注意不能用this调用,事务不会起作用

@Transactional(propagation = Propagation.NOT_SUPPORTED)

public void sub(){

    insertB();  //插入B

    throw RuntimeException;     //发生异常抛出

    insertC();  //调用C

示例6因为当main方法有事务的时候,就会挂起当前事务即main以事务运行,sub不以事务运行

所以最终结果:

A因为sub抛出异常事务回滚,插入失败,B因为不以事务运行插入成功,C因为遇到异常,后续不会执行,所以插入失败。

1

2

3

4

5

6

7

8

9

10

11

// 示例7:

public void main(){

    insertA();  // 插入A

    service.sub();   // 调用其他方法

}

// 两个Service中调用,如果同一个要注意不能用this调用,事务不会起作用

@Transactional(propagation = Propagation.NOT_SUPPORTED)

public void sub(){

    insertB();  //插入B

    throw RuntimeException;     //发生异常抛出

    insertC();  //调用C

示例7这种情况就是所有方法都不会以事务运行,A、B均能插入成功,C无法插入

6. Propagation.NEVER

不使用事务,如果当前事务存在,则抛出异常

1

2

3

4

5

6

7

8

9

10

11

// 示例7:

@Transactional(propagation = Propagation.REQUIRED)

public void main(){

    insertA();  // 插入A

    service.sub();   // 调用其他方法

}

// 两个Service中调用,如果同一个要注意不能用this调用,事务不会起作用

@Transactional(propagation = Propagation.NEVER)

public void sub(){

    insertB();  //插入B

    insertC();  //调用C

sub因为是Never所以是不会执行直接抛出错误,所以main的事务遇到异常直接回滚,所以A回滚无法插入,B、C不会插入。

7. Propagation.NESTED

如果当前事务存在,则在嵌套(父子)事务中执行,否则REQUIRED的操作一样(开启一个事务)

1

2

3

4

5

6

7

8

9

10

11

12

// 示例7:

@Transactional(propagation = Propagation.REQUIRED)

public void main(){

    insertA();  // 插入A

    service.sub();   // 调用其他方法

    throw RuntimeException;     //发生异常抛出

}

// 两个Service中调用,如果同一个要注意不能用this调用,事务不会起作用

@Transactional(propagation = Propagation.NESTED)

public void sub(){

    insertB();  //插入B

    insertC();  //调用C

这个是最需要理解的一种传播机制,要理清楚嵌套(父子)事务,main的是父事务,sub是子事务,main发生异常全部都会回滚。

结果:

A、B、C全部回滚

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

// 示例8:

@Transactional(propagation = Propagation.REQUIRED)

public void main(){

    insertA();  // 插入A

    try {

         service.sub();   // 调用其他方法

    } catch (Exception e) {

    }

    insertD();

}

// 两个Service中调用,如果同一个要注意不能用this调用,事务不会起作用

@Transactional(propagation = Propagation.NESTED)

public void sub(){

    insertB();  //插入B

    throw RuntimeException;     //发生异常抛出

    insertC();  //调用C

示例8,子事务发生异常抛出,但父事务catch掉了,那么这个时候main方法就相当于正常执行没有发生异常,那么就只有子事务回滚。

结果:

A、D插入成功,B、C插入失败

  • REQUIRED
    • 内外同一个事务,任何一个地方抛出异常全部一起回滚。
  • REQUIRED_NEW
    • 内部开启一个新的事务,外部事务回滚并不会影响内部的事务,而如果内部事务抛出被catch也不会影响外部事务。

怎么样快速记忆,七个分四组,221这样记,两个一对互相类似

传播类型含义
group1Propagation.REQUIRED如果当前已有事务则加入当前事务,否则开启新的事务
group1Propagation.REQUIRED_NEW无论当前是否有事务都开启新的事务
group2Propagation.SUPPORTED如果当前事务存在就加入事务,否则以非事务运行
group2Propagation.NOT_SUPPORTED始终以非事务方式执行,如果当前存在事务,则挂起当前事务
group3Propagation.NEVER不使用事务,如果当前事务存在,则抛出异常
group3Propagation.MANDATORY当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。
group4Propagation.NESTED父子(嵌套)事务,父回滚全回滚,子回滚不影响父事务

3.具体案例

单纯讲案例比较枯燥,会觉得工作中什么情况会使用到呢,这边就举一个例子来讲解一下。

在下单时候,我们最主要是写入订单、然后添加积分,最后记录日志

1

2

3

4

5

6

7

8

9

10

11

12

13

@Service

  public class OrderServiceImpl implements OrderService{

       @Transactional

       public void placeOrder(OrderDTO orderDTO){

           try {

               pointService.addPoint(Point point);

           } catch (Exception e) {

              // 记录错误信息

           }

           //省略...

       }

       //省略...

  }

1

2

3

4

5

6

7

8

9

10

11

12

13

@Service

public class PointServiceImpl implements PointService{

     @Transactional(propagation = Propagation.NESTED)

     public void addPoint(Point point){

         try {

             recordService.addRecord(Record record);

         } catch (Exception e) {

            //省略...

         }

         //省略...

     }

     //省略...

}

1

2

3

4

5

6

7

8

@Service

public class RecordServiceImpl implements RecordService{

     @Transactional(propagation = Propagation.NOT_SUPPORTED)

     public void addRecord(Record record){

         //省略...

     }

     //省略...

}

下单的操作不会影响添加积分的操作,所以我们使用NESTED,下单只要成功,添加积分可以成功或失败,失败的话就错误信息后续补偿。而记录日志我们可以有也可以没有,就可以设置为NOT_SUPPORTED不开启事务,使得事务的方法能尽可能的精简,避免一个很大的事务方法。

总结

本文讲解了Spring事务的七种传播机制,我们可以根据具体的类型,具体设置,避免事务的方法过于长,一个事务里面调用的库表越多,就越有可能造成死锁,所以我们要根据具体的需要拆分使用。

相关文章:

关于Spring @Transactional事务传播机制详解

Spring事务传播机制 1.什么是事务传播机制?2.Spring事务传播类型Propagation介绍3.具体案例总结 Spring事务传播机制 1.什么是事务传播机制? 举个栗子,方法A是一个事务的方法,方法A执行过程中调用了方法B,那么方法B有…...

力扣139.单词拆分

思路:动态规划,设dp[]记录当前字符能不能通过字典里的单词到达,双层循环,外层循环遍历字符串每一个字符,内层遍历当前i字符之前的所有以i字符结尾的子串 例如字符串:leetcode i遍历到了t 那么内层循环就…...

Docker 镜像命令总汇

目录 1、查看镜像列表 2、搜索镜像 3、拉取镜像 4、删除镜像 5、显示镜像详细信息 6、显示镜像历史 7、导出镜像 8、导入镜像 9、清理未使用的镜像 10、强制删除镜像 1、查看镜像列表 docker images 这个命令列出了你系统中的所有 Docker 镜像,包括镜像名…...

客户服务:助力企业抵御经济衰退的关键要素与策略

目前经济仍悬而未决是否陷入衰退。当前情况下,尽管通胀率高企,消费者支出良好,就业率也在上升,表明就业市场强劲。然而,有人认为衰退可能会在2024年第一季度发生。经济环境的不确定性可能会让人望而却步,但…...

第八周:AIPM面试准备

以下为从开始准备转行到拿到offer期间每天需要准备的10个面试题目以及相关知识补充!来源广泛,从各个地方收集,只提供题目,我自己的尝试回答也会陆续放在我的喜马拉雅,基于我粗浅的认知,分享我粗浅的作答思路…...

阿里云2核2G3M服务器能放几个网站?有限制吗?

阿里云2核2g3m服务器可以放几个网站?12个网站,阿里云服务器网的2核2G服务器上安装了12个网站,甚至还可以更多,具体放几个网站取决于网站的访客数量,像阿里云服务器网aliyunfuwuqi.com小编的网站日访问量都很少&#xf…...

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机本身的数据保存(CustomData)功能(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机本身的数据保存(CustomData)功能(C#) Baumer工业相机Baumer工业相机的数据保存(CustomData)功能的技术背景CameraExplorer如何使用图像剪切&#xff…...

从零开始配置kali2023环境:镜像保存和导入

对原始的镜像做了一些改动,然后把当前容器状态打包为新的镜像,这样以后可以部署到其他地方了,而不用再安装软件等改动等等 1.查看容器id ┌──(holyeyes㉿kali2023)-[~] └─$ sudo docker ps ┌──(holyeyes㉿kali2023)-[~] └─$ s…...

Transformer梳理与总结

其实transformer的成功也是源于对注意力机制的应用,其本质上还是可以归因于注意力机制,首先我们先来了解一下什么是注意力机制。在注意力机制的背景下,自主性提示被称为查询(query),给定任何查询,注意力机制…...

php之 校验多个时间段是否重复

参考网址 https://www.kancloud.cn/xiaobaoxuetp/mywork/3069416 https://segmentfault.com/a/1190000020487996 PHP判断多个时间段是否存在跨天或重复叠加的场景 /*** PHP计算两个时间段是否有交集(边界重叠不算)** param string $beginTime1 开始时间…...

atoi函数的模拟实现

这里强力推荐一篇文章 http://t.csdnimg.cn/kWuAm 详细解析了atoi函数以及其模拟实现,我这里就不说了。 这里作者先把自己模拟的代码给大家看一下。 int add(char* arr) {char* arr2 arr;while (*arr!-48){arr;}arr--;int sum 0;int n 0;while (arr ! (arr2-…...

编程笔记 html5cssjs 009 HTML链接

编程笔记 html5&css&js 009 HTML链接 一、HTML 链接二、文本链接三、图片链接四、HTML 链接- id 属性五、锚点链接六、HTML 链接 - target 属性七、属性downloadhrefpingreferrerpolicyreltargettype 八、操作小结 网页有了链接,就可根据需要进行跳转。纸质…...

Vue实现导出Excel表格,提示“文件已损坏,无法打开”的解决方法

一、vue实现导出excel 1、前端实现 xlsx是一个用于读取、解析和写入Excel文件的JavaScript库。它提供了一系列的API来处理Excel文件。使用该库,你可以将数据转换为Excel文件并下载到本地。这种方法适用于在前端直接生成Excel文件的场景。 安装xlsx依赖 npm inst…...

分发糖果,Java经典算法编程实战。

🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。 🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。 🎉欢迎 👍点赞✍评论…...

鸿蒙原生应用再添新丁!中国移动 入局鸿蒙

鸿蒙原生应用再添新丁!中国移动 入局鸿蒙 来自 HarmonyOS 微博1月2日消息,#中国移动APP启动鸿蒙原生应用开发#,拥有超3亿用户的中国移动APP宣布,正式基于HarmonyOS NEXT启动#鸿蒙原生应用#及元服务开发。#HarmonyOS#系统的分布式…...

一个人能不能快速搭建一套微服务环境

一、背景 大型软件系统的开发现在往往需要多人的协助,特别是前后端分离的情况下下,分工越来越细,那么一个人是否也能快速搭建一套微服务系统呢? 答案是能的。看我是怎么操作的吧。 二、搭建过程 1、首先需要一套逆向代码生成工…...

计算机毕业设计------经贸车协小程序

项目介绍 本项目分为三种用户类型,分别是租赁者,车主,管理员用户; 管理员用户包含以下功能: 管理员登录,个人中心,租赁者管理,车主管理,赛事活动管理,车类别管理,租车管理,租车订单管理,车辆出售管理,购买订单管理,…...

数据结构OJ实验11-拓扑排序与最短路径

A. DS图—图的最短路径(无框架) 题目描述 给出一个图的邻接矩阵,输入顶点v,用迪杰斯特拉算法求顶点v到其它顶点的最短路径。 输入 第一行输入t,表示有t个测试实例 第二行输入顶点数n和n个顶点信息 第三行起&…...

你的第一个JavaScript程序

JavaScript,即JS,JavaScript是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript基于原型编程、多范式的动态脚本语言…...

CMake入门教程【基础篇】列表操作(list)

文章目录 1. 定义列表2. 获取列表长度3. 获取列表元素4. 追加元素到列表末尾5. 插入元素到指定位置6. 移除指定位置的元素7. 移除指定值的元素8. 替换指定位置的元素9. 迭代列表元素 #mermaid-svg-IAjFPWI6IXEGYmuU {font-family:"trebuchet ms",verdana,arial,sans-…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...