spring事务的7种传播行为——详细介绍

2023-11-01

目录

事务传播行为

1、PROPAGATION_REQUIRED

2、PROPAGATION_SUPPORTS

3、PROPAGATION_MANDATORY

4、PROPAGATION_MANDATORY

5、PROPAGATION_NOT_SUPPORTED

6、PROPAGATION_NEVER

7、PROPAGATION_NESTED

事务传播行为

什么叫事务传播行为?听起来挺高端的,其实很简单。
即然是传播,那么至少有两个东西,才可以发生传播。单体不存在传播这个行为。

事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。
例如:methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。

Spring定义了七种传播行为:

现在来看看传播行为

1、PROPAGATION_REQUIRED

如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
可以把事务想像成一个胶囊,在这个场景下方法B用的是方法A产生的胶囊(事务)。

                     
举例有两个方法: 

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
 methodB();
// do something
}

@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
    // do something
}

单独调用methodB方法时,因为当前上下文不存在事务,所以会开启一个新的事务。
调用methodA方法时,因为当前上下文不存在事务,所以会开启一个新的事务。当执行到methodB时,methodB发现当前上下文有事务,因此就加入到当前事务中来。

2、PROPAGATION_SUPPORTS

如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。
举例有两个方法:

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
 methodB();
// do something
}

// 事务属性为SUPPORTS
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() {
    // do something
}

单纯的调用methodB时,methodB方法是非事务的执行的。当调用methdA时,methodB则加入了methodA的事务中,事务地执行。

3、PROPAGATION_MANDATORY

如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
 methodB();
// do something
}

// 事务属性为MANDATORY
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() {
    // do something
}

当单独调用methodB时,因为当前没有一个活动的事务,则会抛出异常throw new IllegalTransactionStateException(“Transaction propagation ‘mandatory’ but no existing transaction found”);当调用methodA时,methodB则加入到methodA的事务中,事务地执行。

4、PROPAGATION_MANDATORY

                       
使用PROPAGATION_REQUIRES_NEW,需要使用 JtaTransactionManager作为事务管理器。
它会开启一个新的事务。如果一个事务已经存在,则先将这个存在的事务挂起。

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
doSomeThingA();
methodB();
doSomeThingB();
// do something else
}


// 事务属性为REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
    // do something
}

当调用

main{  
methodA();
} 

相当于调用

main(){
    TransactionManager tm = null;
    try{
        //获得一个JTA事务管理器
        tm = getTransactionManager();
        tm.begin();//开启一个新的事务
        Transaction ts1 = tm.getTransaction();
        doSomeThing();
        tm.suspend();//挂起当前事务
        try{
            tm.begin();//重新开启第二个事务
            Transaction ts2 = tm.getTransaction();
            methodB();
            ts2.commit();//提交第二个事务
        } Catch(RunTimeException ex) {
            ts2.rollback();//回滚第二个事务
        } finally {
            //释放资源
        }
        //methodB执行完后,恢复第一个事务
        tm.resume(ts1);
        doSomeThingB();
        ts1.commit();//提交第一个事务
    } catch(RunTimeException ex) {
        ts1.rollback();//回滚第一个事务
    } finally {
        //释放资源
    }
}

在这里,我把ts1称为外层事务,ts2称为内层事务。从上面的代码可以看出,ts2与ts1是两个独立的事务,互不相干。Ts2是否成功并不依赖于 ts1。如果methodA方法在调用methodB方法后的doSomeThingB方法失败了,而methodB方法所做的结果依然被提交。而除了 methodB之外的其它代码导致的结果却被回滚了

5、PROPAGATION_NOT_SUPPORTED

PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作为事务管理器。

                  

6、PROPAGATION_NEVER

总是非事务地执行,如果存在一个活动事务,则抛出异常。

7、PROPAGATION_NESTED

                 

如果一个活动的事务存在,则运行在一个嵌套的事务中。 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。
这是一个嵌套事务,使用JDBC 3.0驱动时,仅仅支持DataSourceTransactionManager作为事务管理器。
需要JDBC 驱动的java.sql.Savepoint类。使用PROPAGATION_NESTED,还需要把PlatformTransactionManager的nestedTransactionAllowed属性设为true(属性值默认为false)。

这里关键是嵌套执行。

@Transactional(propagation = Propagation.REQUIRED)
methodA(){
  doSomeThingA();
  methodB();
  doSomeThingB();
}

@Transactional(propagation = Propagation.NEWSTED)
methodB(){
  ……
}

如果单独调用methodB方法,则按REQUIRED属性执行。如果调用methodA方法,相当于下面的效果:

main(){
    Connection con = null;
    Savepoint savepoint = null;
    try{
        con = getConnection();
        con.setAutoCommit(false);
        doSomeThingA();
        savepoint = con2.setSavepoint();
        try{
            methodB();
        } catch(RuntimeException ex) {
            con.rollback(savepoint);
        } finally {
            //释放资源
        }
        doSomeThingB();
        con.commit();
    } catch(RuntimeException ex) {
        con.rollback();
    } finally {
        //释放资源
    }
}

当methodB方法调用之前,调用setSavepoint方法,保存当前的状态到savepoint。如果methodB方法调用失败,则恢复到之前保存的状态。但是需要注意的是,这时的事务并没有进行提交,如果后续的代码(doSomeThingB()方法)调用失败,则回滚包括methodB方法的所有操作。嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别:
它们非常类似,都像一个嵌套事务,如果不存在一个活动的事务,都会开启一个新的事务。
使用 PROPAGATION_REQUIRES_NEW时,内层事务与外层事务就像两个独立的事务一样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。两个事务不是一个真正的嵌套事务。同时它需要JTA事务管理器的支持。

使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。DataSourceTransactionManager使用savepoint支持PROPAGATION_NESTED时,需要JDBC 3.0以上驱动及1.4以上的JDK版本支持。其它的JTATrasactionManager实现可能有不同的支持方式。

PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 “内部” 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。

另一方面, PROPAGATION_NESTED 开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。

由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back.
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring事务的7种传播行为——详细介绍 的相关文章

  • 动态选择端口号?

    在 Java 中 我需要获取端口号以在同一程序的多个实例之间进行通信 现在 我可以简单地选择一些固定的数字并使用它 但我想知道是否有一种方法可以动态选择端口号 这样我就不必打扰我的用户设置端口号 这是我的一个想法 其工作原理如下 有一个固定
  • HSQL - 识别打开连接的数量

    我正在使用嵌入式 HSQL 数据库服务器 有什么方法可以识别活动打开连接的数量吗 Yes SELECT COUNT FROM INFORMATION SCHEMA SYSTEM SESSIONS
  • Pig Udf 显示结果

    我是 Pig 的新手 我用 Java 编写了一个 udf 并且包含了一个 System out println 其中的声明 我必须知道在 Pig 中运行时该语句在哪里打印 假设你的UDF 扩展了 EvalFunc 您可以使用从返回的 Log
  • 如何在 Spring 中禁用使用 @Component 注释创建 bean?

    我的项目中有一些用于重构逻辑的通用接口 它看起来大约是这样的 public interface RefactorAwareEntryPoint default boolean doRefactor if EventLogService wa
  • 在 Bash 中监控 tomcat,直到它完成部署 war 或应用程序

    怎么可能Tomcat在 bash 脚本中进行监控以检测它是否完成了战争或应用程序的部署 应用场景 Tomcat 开始于systemd Tomcat 开始于catalina sh 使用 Tomcat 管理器 Tomcat从Eclipse启动
  • 来自 dll 的 Java 调用函数

    我有这个 python 脚本导入zkemkeeperdll 并连接到考勤设备 ZKTeco 这是我正在使用的脚本 from win32com client import Dispatch zk Dispatch zkemkeeper ZKE
  • java.lang.IllegalStateException:应用程序 PagerAdapter 更改了适配器的内容,而没有调用 PagerAdapter#notifyDataSetChanged android

    我正在尝试使用静态类将值传递给视图 而不是使用意图 因为我必须传递大量数据 有时我会收到此错误 但无法找出主要原因是什么 Error java lang IllegalStateException The application s Pag
  • 从最终实体获取根证书和中间证书

    作为密码学的菜鸟 我每天都会偶然发现一些简单的事情 今天只是那些日子之一 我想用 bouncy castle 库验证 java 中的 smime 消息 我想我几乎已经弄清楚了 但此时的问题是 PKIXparameters 对象的构建 假设我
  • java.lang.IllegalStateException:提交响应后无法调用 sendRedirect()

    这两天我一直在尝试找出问题所在 我在这里读到我应该在代码中添加一个返回 我做到了 但我仍然得到 java lang IllegalStateException Cannot call sendRedirect after the respo
  • 将 MOXy 设置为 JAXB 提供程序,而在同一包中没有属性文件

    我正在尝试使用 MOXy 作为我的 JAXB 提供程序 以便将内容编组 解组到 XML JSON 中 我创建了 jaxb properties 文件 内容如下 javax xml bind context factory org eclip
  • Eclipse Maven Spring 项目 - 错误

    I need help with an error which make me crazy I started to study Java EE and I am going through tutorial on youtube Ever
  • Hibernate 的 PersistentSet 不使用 hashCode/equals 的自定义实现

    所以我有一本实体书 public class Book private String id private String name private String description private Image coverImage pr
  • volatile、final 和synchronized 安全发布的区别

    给定一个带有变量 x 的 A 类 变量 x 在类构造函数中设置 A x 77 我们想将 x 发布到其他线程 考虑以下 3 种变量 x 线程安全 发布的情况 1 x is final 2 x is volatile 3 x 设定为同步块 sy
  • logcat 中 mSecurityInputMethodService 为 null

    我写了一点android应显示智能手机当前位置 最后已知位置 的应用程序 尽管我复制了示例代码 并尝试了其他几种解决方案 但似乎每次都有相同的错误 我的应用程序由一个按钮组成 按下按钮应该log经度和纬度 但仅对数 mSecurityInp
  • 最新的 Hibernate 和 Derby:无法建立 JDBC 连接

    我正在尝试创建一个使用 Hibernate 连接到 Derby 数据库的准系统项目 我正在使用 Hibernate 和 Derby 的最新版本 但我得到的是通用的Unable to make JDBC Connection error 这是
  • 非 Spring 托管类中 DI 的编译时编织

    我想为标记为的类配置编译时编织 Configurable注释能够将 spring 依赖项注入到初始化的类中new操作员 我不想使用加载时编织 因为我无权访问应用程序服务器的运行脚本 因此无法修改它 另外 我希望能够在测试中使用此类 我的意思
  • 干净构建 Java 命令行

    我正在使用命令行编译使用 eclipse 编写的项目 如下所示 javac file java 然后运行 java file args here 我将如何运行干净的构建或编译 每当我重新编译时 除非删除所有内容 否则更改不会受到影响 cla
  • Spring Boot 无法更新 azure cosmos db(MongoDb) 上的分片集合

    我的数据库中存在一个集合 documentDev 其分片键为 dNumber 样本文件 id 12831221wadaee23 dNumber 115 processed false 如果我尝试使用以下命令通过任何查询工具更新此文档 db
  • Spring Rest 和 Jsonp

    我正在尝试让我的 Spring Rest 控制器返回jsonp但我没有快乐 如果我想返回 json 但我有返回的要求 完全相同的代码可以正常工作jsonp我添加了一个转换器 我在网上找到了用于执行 jsonp 转换的源代码 我正在使用 Sp
  • Java中super关键字的范围和使用

    为什么无法使用 super 关键字访问父类变量 使用以下代码 输出为 feline cougar c c class Feline public String type f public Feline System out print fe

随机推荐

  • 宽带连接已断开

    宽带连接已断开 故障描述 原因分析 解决方案 1 排查线路接触不良 2 排查WI FI开关冲突 3 排查关闭节能以太网功能冲突 3 排除其他网卡冲突 4 排查ipv6协议 和 Ipv4协议冲突 方案一 取消勾选ipv6协议 方案二 重装或者
  • k8s学习-CKS真题-Dockerfile和deployment优化

    目录 题目 环境搭建 解题 Dockerfile deployment yaml 模拟题 参考 题目 Task 1 分析和编辑给定的 Dockerfile cks docker Dockerfile 基于 ubuntu 16 04 镜像 并
  • [转载] 深入理解log机制

    原文 http feihu me blog 2014 insight into log 诊断日志对于定位和修复问题起着至关重要的作用 曾经很傻很天真的认为输出日志就是仅仅调用printf 或者std cerr 而已 简单的不能在简单了 这种
  • “区块链+影视”将会在影视娱乐界刮起怎样的风?

    当一种技术能够渗透到各个产业 并在各个产业都产生巨大的价值的时候 它的潜力和未来价值就会被更多人所追捧 在过去的一年时间里 区块链这一划时代的技术夺目地进入公众视野 被认为是当前最有可能带来颠覆性改变的技术 进入2018年来 区块链行业已更
  • kettle 教程(一):简介及入门

    介绍 kettle 是纯 java 开发 开源的 ETL工具 用于数据库间的数据迁移 可以在 Linux windows unix 中运行 有图形界面 也有命令脚本还可以二次开发 kettle 的官网是 https community hi
  • HCIA笔记整理

    网络基础 什么是网络 网络就是由网络连接设备通过传输介质将网络终端设备连接起来 进行资源共享 信息传递的平台 交换机 交换机是按照通信两端传输信息的需要 用人工或设备自动完成的方法把要传输的信息送到符合要求的相应路由上的技术统称 交换机的作
  • element 表单动态获取性别

    element 动态获取性别 在前端页面里总是会有根据1和2显示相应的内容 我是小白刚接触这些就感觉无能为力 找了一些资料才有了解决方法 话不多说上代码
  • Postgresql时间处理技巧,每半天,每周,每月和每5分钟统计

    一 每半天 如果有张表log bus runinfo里有一个created date是timestamp类型 如何统计12点前的数据 在 PostgreSQL 中 您可以使用 DATE TRUNC 函数和 WHERE 子句来统计特定时间范围
  • opsForList().rightPushAll 是覆盖,还是添加

    opsForList rightPushAll 是添加 这个方法将给定的所有值添加到列表的最右端 它并不会覆盖列表中已有的任何值
  • while(++i)与 while(i++)

    1 while i 是先执行i 1 再进行判断 再执行循环体 2 while i 是先判断 再执行循环体 再 1 循环结束后 while i 执行完后 i 0 while i 执行完后 i 1 测试代码1 include
  • 正大国际琪貨:做股指期货需要多少保证金?

    股指之前是大户才有机会做 因为需要的条件太高了 一般人玩不来 为什么 看看国内的股指条件 股指的保证金比例是12 14 一手股指保证金大约18万元 啥 这是什么概念 怎么这么贵 哈哈 是不是已经把很多人吓跑了 但这东西 波动的一个点值也很大
  • LSTM简单例子(MATLAB code)

    最近在学习RNN和LSTM 1 http magicly me 2017 03 09 iamtrask anyone can code lstm 2 https zybuluo com hanbingtao note 581764 3 ht
  • GLTF中的Draco编译与测试

    1 GLTF Primitive primitive里面有什么属性 Draco压缩是跟GLTF Primitive primitive息息相关的 下面是 GLTF Primitive 中常见的属性 1 GLTF Accessor indic
  • 12C++11多线程编程之原子操作std::atomic

    1 原子操作std atomic相关概念 前言 原子操作 更小的代码片段 并且该片段必定是连续执行的 不可分割 1 1 原子操作std atomic与互斥量的区别 1 互斥量 类模板 保护一段共享代码段 可以是一段代码 也可以是一个变量 2
  • Docker镜像打包及解压(内外网)

    背景 在企业中往往出现了内网不能和外网相通 不能使用docker pull命令来拉取镜像 这个时候我们就可以考虑在有所需镜像的服务器上导出镜像 再将其上传到内网服务器上 有两种方法 一种是通过容器 一种是通过镜像 其实本质是一样的 容器的实
  • Tomcat配置出错:Using CATALINA_OPTS: ““&&Tomcat启动闪退问题解决

    文章目录 前言 一 问题描述 二 定位问题 1 CMD命令启动 2 解决方法 前言 本篇问题所处环境 Tomcat 9 Java11 Win 10 一 问题描述 在安装配置Tomcat过程中 通过startup bat脚本命令启动Tomca
  • javascript 清除字符串空格

    去除字符串前后的空格 function trim str return str replace s s g 去除字符串中所有空格 function removeAllSpace str return str replace s g 用法举例
  • 服务器散列值与文件,服务器计算的散列值和客户端安全

    服务器计算的散列值和客户端安全 内容精选 换一换 执行adc命令 系统内部通过ADC与运行环境上的ADA的交互 实现文件传输 设置日志级别 心跳检测等功能 在ADC与ADA交互时 涉及使用密钥证书实现ADA 作为服务端 和ADC 作为客户端
  • Mysql 显示替换 if or

    摘要 使用Mysql的进行sql查询过程中 经常会遇到对查询结果做一些显示的替换 方式一 select if value in 0 1 2 NO YES from table name 方式二 select if value 0 or va
  • spring事务的7种传播行为——详细介绍

    目录 事务传播行为 1 PROPAGATION REQUIRED 2 PROPAGATION SUPPORTS 3 PROPAGATION MANDATORY 4 PROPAGATION MANDATORY 5 PROPAGATION NO