【老王读Spring Transaction-5】Spring事务传播行为propagation behavior的实现原理

news2025/2/27 8:31:59

Spring事务传播行为propagation behavior的实现原理

  • 前言
  • Spring 版本
  • 正文
    • 事务传播行为(propagation behavior)列举
    • 事务传播行为归类
    • 事务传播行为的实现原理
  • 小结

前言

Spring 对事务的封装除了实现了基本的事务管理之外,还提供了事务传播行为(propagation behavior)的高级特性。

通常,事务范围内的所有代码都会在该事务中运行。但是,如果在事务上下文已经存在的情况下再去执行其他事务方法,则可以指定事务的传播行为
例如,代码可以在现有事务中继续运行(常见情况),或者可以暂停现有事务并创建新事务。

事务传播行为的作用是将多个事务操作进行合并或者隔离。

Spring 版本

spring-tx 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)

正文

Spring 中定义的事务传播行为的作用是将多个事务操作进行合并或者隔离。
举个例子,比如:两个事务方法 t1(), t2(),t1 调用了 t2,那么事务应当如何处理?
这里可以有多种处理方式,比如:

  • t1 开启一个事务,t2 在 t1 的事务里面执行;
  • t1 开启一个事务,t2 开启另外一个新事务;
  • t1 开启一个事务,t2 以非事务的方式执行;
    等等

对事务传播行为的理解可以参考官方文档: https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#tx-propagation

这种情况下,就需要使用到 Spring 的事务传播行为特性。

class AService {
   @Autowired
   BService bService;

   @Transactional
   public void t1() {
        ...
        bService.t2();
        ...
   }
}

class BService {

   @Transactional
   public void t2() {
        ...
   }
}

事务传播行为(propagation behavior)列举

Spring 中的事务传播行为共有 7 种,都是在 TransactionDefinition 中进行定义的:

 /** 【默认】支持当前事务;如果当前不存在事务,则创建一个新事务。(默认的事务传播行为)*/
 int PROPAGATION_REQUIRED = 0;

 /**
  * 【支持事务】支持当前事物,如果当前没有事物,就以非事物方式执行。
  * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
  * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
  */
 int PROPAGATION_SUPPORTS = 1;

 /** 【强制使用事务】使用当前的事物,如果当前不存在事物,就抛出异常。 */
 int PROPAGATION_MANDATORY = 2;

 /**
  * 【隔离多个事务】创建一个新事物,如果当前存在事物,把当前事物挂起。
  * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
  */
 int PROPAGATION_REQUIRES_NEW = 3;

 /**
  * 【强制非事务】不支持当前事务,始终以非事务方式执行。
  * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
  */
 int PROPAGATION_NOT_SUPPORTED = 4;

 /** 【不支持事务】不支持当前事务;如果当前事务存在,则抛出异常。 */
 int PROPAGATION_NEVER = 5;

 /**
  * 【嵌套事务】如果当前存在事物,则在嵌套事物内执行,支持按指定范围回滚事务(通过 savepoint 机制来实现);如果当前没有事物,新建一个事务。
  * 注意:嵌套事务的实际创建只适用于特定的事务管理器,比如 DataSourceTransactionManager 在使用 JDBC 3.0 driver 时。
  * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
  */
 int PROPAGATION_NESTED = 6;

org.springframework.transaction.TransactionDefinition
org.springframework.transaction.annotation.Propagation

事务传播行为归类

我们可以将事务传播行为归为三类:

  1. 支持当前事务
    int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;

  2. 不支持当前事务
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;

  3. 嵌套事务
    int PROPAGATION_NESTED = 6;

详细的特性如下:

// 支持当前事务
int PROPAGATION_REQUIRED = 0;  // 【默认】支持当前事务;如果当前不存在事务,则创建一个新事务。
int PROPAGATION_SUPPORTS = 1;  // 【支持事务】支持当前事物,如果当前没有事物,就以非事物方式执行。
int PROPAGATION_MANDATORY = 2; // 【强制使用事务】使用当前的事物,如果当前没有事物,就抛出异常。 

// 不支持当前事务
int PROPAGATION_REQUIRES_NEW = 3;  // 【隔离多个事务】创建一个新事物,如果当前存在事物,把当前事物挂起。  
int PROPAGATION_NOT_SUPPORTED = 4; //  【强制非事务】不支持当前事务,始终以非事务方式执行。 
int PROPAGATION_NEVER = 5;  // 【不支持事务】以非事物方式执行,如果当前存在事物,则抛出异常。 

// 嵌套事务
int PROPAGATION_NESTED = 6; // 【嵌套事务】如果当前存在事物,则在嵌套事物内执行,支持按指定范围回滚事务(通过 savepoint 机制来实现);如果当前没有事物,新建一个事务。

Spring 是采用保存点(Savepoint)来实现 NESTED 嵌套事务的。Savepoint 可以指定范围提交事务。

事务传播行为的实现原理

org.springframework.transaction.annotation.Propagation 中的枚举值是 TransactionDefinition 中定义的常量。比如: TransactionDefinition.PROPAGATION_REQUIRES_NEW

我们可以通过找 TransactionDefinition.PROPAGATION_REQUIRES_NEW 被使用的地方,可以找到 AbstractPlatformTransactionManager#getTransaction()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yC3mUB7z-1676436265805)(https://s2.51cto.com/images/20220811/1660188464429779.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)]

首先,doGetTransaction() 会获取到一个事务对象,通常是 DataSourceTransactionObject
然后,会判断当前线程中是否存在事务

当在事务方法当中执行另外一个 @Transactional 标记的事务方法时,不同的事务传播行为的处理逻辑如下:
handleExistingTransaction.png

可以看到,如果当前线程中存在事务的话,在事务方法中再去调用另外一个 @Transactional 方法时,会根据不同的事务传播行为进行处理:
1、如果是 PROPAGATION_NEVER,则会直接抛出异常
2、如果是 PROPAGATION_NOT_SUPPORTED,则会将当前的事务挂起,再另起一个连接,以非事务的方式去执行
3、如果是 PROPAGATION_REQUIRES_NEW,则会将当前事务挂起,然后另起一个事务去执行
4、如果是 PROPAGATION_NESTED,则会以嵌套事务的方式执行,支持按指定范围回滚事务。(通过 savepoint 机制来实现)

小结

Spring 中定义的事务传播行为的作用是将多个事务操作进行合并或者隔离。
Spring 的事务传播行为可以分为三类:一,支持当前事务;二,不支持当前事务;三,嵌套事务。

// 支持当前事务
int PROPAGATION_REQUIRED = 0;  // 【默认】支持当前事务;如果当前不存在事务,则创建一个新事务。
int PROPAGATION_SUPPORTS = 1;  // 【支持事务】支持当前事物,如果当前没有事物,就以非事物方式执行。
int PROPAGATION_MANDATORY = 2; // 【强制使用事务】使用当前的事物,如果当前没有事物,就抛出异常。 

// 不支持当前事务
int PROPAGATION_REQUIRES_NEW = 3;  // 【隔离多个事务】创建一个新事物,如果当前存在事物,把当前事物挂起。  
int PROPAGATION_NOT_SUPPORTED = 4; //  【强制非事务】不支持当前事务,始终以非事务方式执行。 
int PROPAGATION_NEVER = 5;  // 【不支持事务】以非事物方式执行,如果当前存在事物,则抛出异常。 

// 嵌套事务
int PROPAGATION_NESTED = 6; // 【嵌套事务】如果当前存在事物,则在嵌套事物内执行,支持按指定范围回滚事务(通过 savepoint 机制来实现);如果当前没有事物,新建一个事务。

事务传播行为的实现是通过 TransactionStatus AbstractPlatformTransactionManager#getTransaction() 来实现的。
当 @Transactional 方法出现嵌套调用时,Spring 会根据不同的事务传播行为创建不同的 TransactionStatus,来控制是否使用同一个连接,是否共用同一个事务 或者 是不使用事务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/347362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【STM32笔记】HAL库外部定时器、系统定时器阻塞、非阻塞延时

【STM32笔记】HAL库外部定时器、系统定时器阻塞、非阻塞延时 外部定时器 采用定时器做延时使用时 需要计算好分频和计数 另外还要配置为不进行自动重载 对于50MHz的工作频率 分频为50-1也就是50M/501M 一次计数为1us 分频为50000-1也就是1k 一次计数为1ms 我配置的是TIM6 只…

深度学习——自注意力机制和位置编码(笔记)

1.自注意力: ①在深度学习中,经常使用卷积神经网络或者循环神经网络对序列进行编码 ②对于key,value和query,自注意力有一套自己的选法,因为key,value和query的值来自同一组输入。因此被称为自注意力或内部注意力 2…

CDGA|数据治理为什么绕不开数据权责问题?如何确定数据权责?

许多企业在经历过信息化建设之后,自然而然地将数据管理的重任交付给了IT部门,而当企业数据质量产生问题时,高层管理者也往往将其归结为IT部门的责任。然而,企业IT部门真的能够管理好这些数据,使其发挥最大效能吗&#…

在 Kubernetes 上运行《我的世界》

最近给小朋友装上了叨叨许久的 Minecraft(我的世界),为了体验安装的是开源启动器 HMCL。其实这游戏我也关注比较久了,不过感觉太耗时间。但被小朋友拉上一起玩,便研究了下自建服务器。GitHub 发现已经有人做好了 Minec…

操作系统(四):磁盘调度算法,先来先服务,最短寻道时间优先,电梯算法

文章目录一、磁盘结构二、先来先服务三、最短寻道时间优先四、电梯算法 SCAN一、磁盘结构 盘面(Platter):一个磁盘有多个盘面; 磁道(Track):盘面上的圆形带状区域,一个盘面可以有多…

大数据处理学习笔记1.2 Scala变量与数据类型

文章目录零、本讲学习目标一、变量声明(一)简单说明(二)利用val声明变量1、声明方式2、案例演示(三)利用var声明变量1、声明方式2、案例演示(四)换行输入语句(续行&#…

生产故障|Kafka ISR频繁伸缩引发性能急剧下降

生产故障|Kafka ISR频繁伸缩引发性能急剧下降-阿里云开发者社区 本文是笔者双十一系列第二弹,源于一个双十一期间一个让笔者猝不及防的生产故障,本文将详细剖析Kafka的副本机制,以及ISR频繁变更(扩张与伸缩)为什么会导致集群不可…

深入浅出C++ ——queue类深度剖析

文章目录一、queue的简介二、queue类常用接口三、STL中queue类的模拟实现一、queue的简介 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。队列作为容器适配器实现,容器适配…

【RNN详解】SimpleRNN,LSTM,bi-LSTM的原理及Tensorflow实现

目录1.摘要2.SimpleRNN2.1.原理介绍2.2.代码实现3.LSTM3.1.原理介绍3.2.代码实现4.LSTM改进—bi_LSTM5.总结感觉不错的话,记得点赞收藏啊。1.摘要 RNN是一种特殊的神经网络结构,它是根据“人的认知是基于过往的经验和记忆”这一观点提出的,它…

node.js+vue图书销售租赁书店运营管理系统mysql vscode

图书销售租赁书店运营管理系 前端技术:nodejsvueelementui,视图层其实质就是vue页面,通过编写vue页面从而展示在浏览器中,编写完成的vue页面要能够和控制器类进行交互,从而使得用户在点击网页进行操作时本图书馆租赁管理系统主要分…

面向新手的git实战教程

嗨!我是团子,大家好久不见呀~ 记得之前在网上学习git相关知识时,看到的文章大部分都是讲解git的基本命令有哪些,用处是什么,但是自己真正上手使用git时,仍然无从下手。 所以今天就想从初始化一个git仓库开始…

Quartz 快速入门案例,看这一篇就够了

前言 Quartz 是基于 Java 实现的任务调度框架,对任务的创建、修改、删除、触发以及监控这些操作直接提供了 api,这意味着开发人员拥有最大的操作权,也带来了更高的灵活性。 什么是任务调度? 任务调度指在将来某个特定的时间、固…

rabbitmq topic模式设置#通配符情况下 消费者队列未接收消息问题排查解决

目录说明说明 生产者配置 Exchange:topic_exchange_shcool Routing key:topic.shcool.# 消费者代码配置 Exchange:topic_exchange_shcool Routing key:topic.shcool.user PostConstructpublic void twoRabbitInit() {//声明交换…

基于微信小程序云开发实现考研题库小程序项目(完整版)

今天手把手的带大家实现一款答题类的题库小程序,如果着急的话,可以直接去看文末源码.下载与项目部署。考研题库小程序云开发实战,完整版提供给大家学习。题库小程序,基于云开发的微信答题小程序,软件架构是微信原生小程…

YOLOv8进行改进并训练自定义的数据集

一.训练数据集准备 YOLOv8的训练数据格式与YOLOv5的训练数据格式一致,这一部分可以进行沿用。之前博文有发布VOC标注格式转YOLO标注格式的脚本,有需要可以查看。 二.项目克隆 YOLOv8项目文件可以直接去github上下载zip文件然后解压,也可以直…

Telerik UI for WPF 2023 R1

Telerik UI for WPF 2023 R1 之 WPF 的 Telerik 用户界面,WPF 控件库开发人员信任,快速构建美观、高性能的 WPF 业务应用程序。现在支持 .NET 6 和 7.0。 概述部分背景图像 主要特征 现代专业主题图标,现代专业主题 通过各种受 Office、Wind…

【机器学习】P0 基础与相关名词

机器学习基础与相关名词什么是机器学习监督学习与非监督学习Classification And RegressionClusteringModel and Function什么是机器学习 机器学习是计算机发展到一定阶段的必然产物。相比于19世纪一个房间大小的计算机,当前的计算机更便携,性能更强&am…

开源项目-旅游信息管理系统

哈喽,大家好,今天给大家带来一个开源系统-旅游信息管理系统 前台 地址:http://ip/index 账号:user 密码:123456 后台 地址:http://ip/login 账号:root 密码:123456 功能模块:旅游路线、旅游景点、旅游酒店、旅游车票、旅游保险、旅游策略、订单管理、留言管理、数据…

一篇解决Linux 中的负载高低和 CPU 开销并不完全对应

负载是查看 Linux 服务器运行状态时很常用的一个性能指标。在观察线上服务器运行状况的时候,我们也是经常把负载找出来看一看。在线上请求压力过大的时候,经常是也伴随着负载的飙高。 但是负载的原理你真的理解了吗?我来列举几个问题&#x…

c/c++开发,无可避免的模板编程实践(篇二)

一、开发者需要对模板参数负责 1.1 为您模板参数提供匹配的操作 在进行模板设计时,函数模板或类模板一般只做模板参数(typename T)无关的操作为主,但是也不见得就不会关联模板参数自身的操作,尤其是在一些自定义的数据…