【 Spring 事务传播机制 】

news2024/9/22 17:26:56

文章目录

  • 一、概念
  • 二、为什么需要事务传播机制?
  • 三、事务传播机制有哪些?
  • 四、Spring 事务传播机制使⽤和各种场景演示
    • 4.1 ⽀持当前事务(REQUIRED)
    • 4.2 不⽀持当前事务(REQUIRES_NEW)
    • 4.3 NESTED 嵌套事务
    • 4.4 嵌套事务和加⼊事务的区别

一、概念

Spring 事务传播机制是指多个包含事务的⽅法相互调⽤时,事务是如何在这些⽅法间进⾏传递的

二、为什么需要事务传播机制?

事务隔离级别是保证多个并发事务执⾏的可控性(稳定性的),⽽事务传播机制是保证⼀个事务在多个调⽤⽅法间传递的可控性

事务隔离级别解决的是多个事务同时调⽤⼀个数据库的问题,如下图所示:
在这里插入图片描述

⽽事务传播机制解决的是⼀个事务在多个节点(⽅法)中传递的问题,如下图所示:
在这里插入图片描述

三、事务传播机制有哪些?

Spring 事务传播机制包含以下 7 种:

  1. Propagation.REQUIRED:默认的事务传播级别,它表示如果当前存在事务,则加⼊该事务;如果当前没有事务,则创建⼀个新的事务。
  2. Propagation.SUPPORTS:如果当前存在事务,则加⼊该事务;如果当前没有事务,则以⾮事务的⽅式继续运⾏。
  3. Propagation.MANDATORY:(mandatory:强制性)如果当前存在事务,则加⼊该事务;如果当前没有事务,则抛出异常。
  4. Propagation.REQUIRES_NEW:表示创建⼀个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部⽅法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部⽅法会新开启⾃⼰的事务,且开启的事务相互独⽴,互不⼲扰。
  5. Propagation.NOT_SUPPORTED:以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起。
  6. Propagation.NEVER:以⾮事务⽅式运⾏,如果当前存在事务,则抛出异常。
  7. Propagation.NESTED:如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏;如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED。

以上 7 种传播⾏为,可以根据是否⽀持当前事务分为以下 3 类:
在这里插入图片描述

如何理解当前事务?举个例子:

方法A(包含事务a) 去调用 方法B(包含事务b) ,此时A就是外部方法,而a就是外部方法事务即所谓的当前事务,而B就是内部方法,b就是内部方法事务。所以所谓的当前事务,就是外部方法的事务

上面说的很抽象,我们通过具体的代码来说明,如下

四、Spring 事务传播机制使⽤和各种场景演示

目标实现:当在用户表中添加一条数据后,相应的日志表也会记录一条消息

正确的业务代码是当我添加用户成功时就会自动添加一条日志,所以直接在一个service里调用这两个添加接口就行了。而下面我们为了验证事务的传播机制特意将用户添加和日志添加方法分开,分别在 controller 中调用 !!

准备工作:

  1. 创建用户表和日志表
    在这里插入图片描述

  2. 准备相应的实体类
    在这里插入图片描述

  3. mapper 代码实现
    在这里插入图片描述

  4. xml 文件实现

<insert id="add">
    insert into loginfo(name,description)
    values (#{name}, #{description})
</insert>
<insert id="add">
    insert into userinfo(username,password) values (#{username},#{password})
</insert>
  1. controller 代码实现
@RestController
public class UserController {
    @Resource
    private UserService userService;

    @Resource
    private LogService logService;
    
    @Transactional(propagation = Propagation.REQUIRED) //默认就是 REQUIRED
    @RequestMapping("/add3")
    public int add3(UserInfo userInfo) {
        if (userInfo == null ||
                !StringUtils.hasLength(userInfo.getUsername()) ||
                !StringUtils.hasLength(userInfo.getPassword())) {
            return 0;
        }
        int userResult = userService.add(userInfo);
        System.out.println("添加用户:" + userResult);
        LogInfo logInfo = new LogInfo();
        logInfo.setName("添加用户的姓名");
        logInfo.setDescription("添加用户结果:" + userResult);
        int logResult = logService.add(logInfo);
        return userResult;
    }
}

具体 service 代码实现,以及验证结果

4.1 ⽀持当前事务(REQUIRED)

以下代码实现中,先开启事务先成功插⼊⼀条⽤户数据,然后再执⾏⽇志报错,⽽在⽇志报错是发⽣了异常,观察 propagation = Propagation.REQUIRED 的执⾏结果

UserService 实现代码如下:

@Service
public class UserService {
    @Resource
    private UserInfoMapper userInfoMapper;

    @Transactional(propagation = Propagation.REQUIRED)
    public int add(UserInfo userInfo){
        return userInfoMapper.add(userInfo);
    }
}

LogService 实现代码如下:

@Service
public class LogService {

    @Resource
    private LogInfoMapper logInfoMapper;

    @Transactional(propagation = Propagation.REQUIRED)
    public int add(LogInfo logInfo) {
        int result = logInfoMapper.add(logInfo);
        System.out.println("添加日志结果:" + result);
        int number = 10 / 0;
        return result;
    }
}

验证前的数据表:
在这里插入图片描述

通过 url 访问,控制台结果:
在这里插入图片描述

再次查看数据表:
在这里插入图片描述

我们发现,两张数据表都没有成功插入数据,没有存在异常的添加用户操作也同样失败了。这是为什么呢?

这是因为我们将两个添加方法上的事务都设置成了 REQUIRED ,而在前面我们知道了它表示如果当前存在事务,则加⼊该事务;如果当前没有事务,则创建⼀个新的事务。而 controller 中的添加方法我们设置了事务的,该添加方法调用了用户添加和日志添加方法,所以他们两的事务直接加入到了外部方法事务中,成为了一个整体!现在他们处于同一事务中,当添加日志操作出现异常后进行回滚操作,整个事务都会实现回滚操作,所以用户添加操作也会回滚,用户添加操作失败


4.2 不⽀持当前事务(REQUIRES_NEW)

UserController 类中的代码不变,将添加⽤户和添加⽇志的⽅法修改为 REQUIRES_NEW 不⽀持当前事务,重新创建事务,观察执⾏结果

重复代码就不写了,只需要将两个添加方法中的事务的传播机制设置为 REQUIRES_NEW

通过 url 访问,控制台结果:
在这里插入图片描述

查看数据表结果
在这里插入图片描述

我们发现,用户表中成功插入了数据,而日志表中还是为空!!

分析如下,我们将两个添加方法的事务传播机制设置为了 REQUIRES_NEW,它表示创建⼀个新的事务,如果当前存在事务,则把当前事务挂起。即外部方法事务是否存在已经不重要了,两个添加方法都创建了各自的事务,且互不干扰。所以添加日志操作出现异常,它的事务就会进行回滚操作,而该回滚操作并不会影响处于另一个事务的添加用户操作 ! 所以用户添加能够成功,而日志添加失败


4.3 NESTED 嵌套事务

老样子,重复代码就不写了,只需要将两个添加方法中的事务的传播机制设置为 NESTED
并使用 try…catch 将添加日志中的异常捕获(使用 NESTED 的前提) 如下:

logservice 代码修改

@Service
public class LogService {
    @Resource
    private LogInfoMapper logInfoMapper;

    @Transactional(propagation = Propagation.NESTED)
    public int add(LogInfo logInfo) {
        int result = logInfoMapper.add(logInfo);
        System.out.println("添加日志结果:" + result);
        try {
            int number = 10 / 0;
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return result;
    }
}

通过 url 访问,控制台结果:
在这里插入图片描述

查看数据表结果:
在这里插入图片描述

用户添加操作成功,而日志添加操作失败 !!由此可见,日志添加事务已经回滚,但是该嵌套事务不会回滚嵌套之前的事务即外部方法事务,也就是说嵌套事务可以实现部分事务回滚!!

那嵌套事务是如何实现部分事务回滚的呢?嵌套事务只所以能够实现部分事务的回滚,是因为事务中有⼀个保存点(savepoint)嵌套事务进⼊之后相当于新建了⼀个保存点,⽽滚回时只回滚到当前保存点,因此之前的事务是不受影响的。⽽ REQUIRED 是加⼊到当前事务中,并没有创建事务的保存点,因此出现了回滚就是整个事务回滚,这就是嵌套事务和加⼊事务的区别

(重要) 前面我们说使用 try…catch 将添加日志中的异常捕获是使用 NESTED 的前提,如果不这样做的话日志添加中的回滚操作会持续往上找调⽤它的⽅法和事务进行回滚,最终我们的外部方法事务也会被回滚,所以即使用户添加操作没有异常出现,该操作也会被回滚,最终的结果是⽤户表和⽇志表都没有添加任何数据 !!

与嵌套事务相关文档 !!!


4.4 嵌套事务和加⼊事务的区别

前面我们分别演示了这两种事务,也对各自的结果进行了分析

REQUIRED 是如果当前存在事务就加入该事务,成为该事务的一部分,既然都是一家人了,大家有难一起担!所以当其中的一个事务出现异常进行了回滚操作,那么整个事务都将会进行回滚操作。而 NESTED 是如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏,即附属在当前事务,并没有真正的成为一家人,所以当这个附属事务进行回滚操作时,当前事务并不会进行回滚,也就是说嵌套事务可以实现部分事务回滚 !!

总结如下:

  1. 整个事务如果全部执⾏成功,⼆者的结果是⼀样的。
  2. 如果事务执⾏到⼀半失败了,那么加⼊事务整个事务会全部回滚;⽽嵌套事务会局部回滚,不会影响上⼀个⽅法中执⾏的结果

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

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

相关文章

软考软件设计师 软件工程笔记

软件工程 CMM&#xff08;能力成熟度模型&#xff09;CMMI&#xff08;能力成熟度模型集成&#xff09;瀑布模型V模型&#xff08;质量保证&#xff09;增量模型演化模型&#xff08;迭代更新&#xff09;原型模型螺旋模型&#xff08;风险分析&#xff09;喷泉模型统一过程&am…

大数据编程实验二:熟悉常用的HDFS操作

实验目的 1、理解HDFS在Hadoop体系结构中的角色 2、熟悉使用HDFS操作常用的Shell命令 3、熟悉HDFS操作常用的Java API 实验平台 1、操作系统&#xff1a;Windows 2、Hadoop版本&#xff1a;3.1.3 3、JDK版本&#xff1a;1.84、Java IDE&#xff1a;IDEA 实验步骤 前期&#x…

Springboot整合WebSocket(纯后端)

文章目录 一、 HTTP协议与WebSocket区别二、客户端&#xff08;浏览器&#xff09;实现1、websocket对象2、websocket事件3、WebSocket方法 三、服务端实现1、连接过程2、服务端接收客户端消息3、服务端推送消息给客户端 四、后端功能实现 一、 HTTP协议与WebSocket区别 HTTP协…

如何在家自学编程成为一名程序员?

转自&#xff1a;如何在家自学编程&#xff0c;成为一名优秀的程序员&#xff1f; - 知乎 跟着黑马程序员学&#xff0c;自学也可以很优秀。先找到方向—>前/后端&#xff1f;测试&#xff1f;还是什么&#xff1f;—>找到相关的学习路线 —> 坚持不懈的学习 —> …

论文学习——Video LDM (Align your Latents)

Align your Latents: High-Resolution Video Synthesis with Latent Diffusion Models 0. 来源 本文是阅读论文后的个人笔记&#xff0c;适应于个人水平&#xff0c;叙述顺序和细节详略与原论文不尽相同&#xff0c;并不是翻译原论文。 如果想了解所有细节&#xff0c;建议移…

华为OD机试真题(Java),旋转数组的最小数字(100%通过+复盘思路)

一、题目描述 有一个长度为 n 的非降序数组&#xff0c;比如[1,2,3,4,5]&#xff0c;将它进行旋转&#xff0c;即把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;变成一个旋转数组&#xff0c;比如变成了[3,4,5,1,2]&#xff0c;或者[4,5,1,2,3]这样的。请问&#xf…

Filter 的使用

把对资源的请求拦截下来&#xff0c;从而实现一些特殊功能 &#xff0c;比如需要先登录再使用其他功能 拦截对资源的请求 放行后&#xff0c;执行完资源&#xff0c;再执行放行后的逻辑 按字符比较升序排序&#xff0c;值小的优先级高 FilterDemo优先级高于FilterDemo2 Listene…

华为OD机试真题(Java),最长的连续子序列(100%通过+复盘思路)

一、题目描述 有N个正整数组成的一个序列&#xff0c;给定一个整数sum&#xff0c;求长度最长的的连续子序列使他们的和等于sum&#xff0c;返回该子序列的长度&#xff0c;如果没有满足要求的序列返回-1。 二、输入描述 第1行有N个正整数组成的一个序列。 第2行给定一个整…

[MySQL]基础知识笔记(数据库与表操作)

内存与硬盘的区别&#xff1a; 内存&#xff1a;容量小&#xff0c;速度快&#xff0c;造价高&#xff0c;断电后数据丢失硬盘&#xff1a;容量大&#xff0c;速度慢&#xff0c;造价低&#xff0c;断电后数据不丢失 常见的关系型数据库&#xff1a; 1.ACCESS-微软出的在OFF…

【RPA开发】Beautiful Soup 使用详解

爬虫时通过 requests.get 方法获得 html 源代码后&#xff0c;通常需要从源代码中提取关键信息&#xff0c;这有多种方式&#xff0c;比如使用正则表达式匹配&#xff0c;也可通过 python 的第三方库 Beautiful Soup 实现定位提取关键信息&#xff0c;类似的库还有 lxml 第三方…

如何配置java环境以及tomcat详细步骤

jdk 下载安装及配置 jdk 官网地址: https://www.oracle.com/java/(opens new window) #1、jdk 下载 进入官网,定位到:Java -> Java SE -> Oracle JDK 点击进入,如下图所示: 选择 Java archive,再鼠标下拉页面,选择 Java SE 8 (8u202 and earlier) 下载 jdk-8u2…

一款综合地图应用Vue组件,内置了百度、高德、天地图瓦片

一、开源项目简介 新德汇地图应用类库 基于Openlayers的地图应用Vue组件。内置了百度、高德、天地图瓦片&#xff0c;并支持与方正、超图、山海经纬、航天精一等PGIS厂商对接。包含文本、图形、html、热力图、轨迹回放等20个组件&#xff0c;支持与ECharts结合实现散点、飞行…

scratch电子画板 少儿编程 电子学会图形化编程scratch编程等级考试二级真题和答案解析2023年3月

目录 scratch电子画板 一、题目要求 1、准备工作 2、功能实现 二、案例分析

12.java程序员必知必会类库之HTML解析库

前言 HTML是开发经常遇见的一种报文格式。但是我们日常中&#xff0c;更多是用它来渲染数据。利用他的很多各种标签&#xff0c;格式化我们的数据。一般前端接触的比较多。 但是&#xff0c;随着爬虫技术在互联网上越来越流行&#xff0c;如何处理我们爬到的HTML。。。我们当…

[DASCTF Apr.2023 X SU战队2023开局之战] crypto复现

感觉突然啥都不会了,后来拿到官方WP,也没整明白,这官方的WP没有代码只讲了些道理,复现一下也不容易。 1&#xff0c;easySign 这是个自制的签名题。 from secret import r, t from Crypto.Util.number import *flag bxxx flag bytes_to_long(flag) e 0x10001def gen_keys…

53.网页设计规则#2_配色

选择正确的颜色 让主色调与你的网站个性相匹配&#xff1a;颜色传递意义 a. 红色吸引了很多人的注意&#xff0c;象征着权力、激情和兴奋。 b. 橙色不那么具有攻击性&#xff0c;并传达出幸福、愉快和创造性。 c. 黄色意味着快乐、光明和智慧 d. 绿色代表和谐、自然、成长和健康…

数学建模第六天:数学建模算法篇之插值及MATLAB实现

目录 一、前言 1、引例 2、插值与拟合模型 二、插值 1、插值相关定义 2、拉格朗日插值 3、分段线性插值 4、matlab实现 5、二维插值及matlab实现 一、前言 1、引例 伍老师最近苦不堪言&#xff0c;最近胡吃海喝&#xff0c;管不住嘴&#xff0c;感觉自己最近张胖了&am…

【数据去重】海量数据实时去重方案

文章目录 Prologue布隆过滤器去重什么是布隆过滤器实现的核心思想怎么理解 内嵌RocksDB状态后端去重引入外部K-V存储去重 Prologue 数据去重&#xff08;data deduplication&#xff09;是我们大数据攻城狮司空见惯的问题了。除了统计UV等传统用法之外&#xff0c;去重的意义更…

信号完整性分析基础知识之传输线和反射(四):不连续点和端接

每当信号遇到阻抗变化&#xff0c;就会出现反射现象&#xff0c;反射对信号质量影响很大。信号完整性工作最重要的部分之一就是预测不连续点对信号的影响&#xff0c;以及设计工程可接受的备选方案。 尽管电路板在设计上是可控阻抗互连&#xff0c;但是信号在以下结构中仍然会遇…

如何选择最佳的实时聊天软件

在客户服务和支持领域&#xff0c;实时聊天正在改变游戏规则已不是什么秘密。从推动销售到提升客户体验和提高保留率&#xff0c;实时聊天已成为与客户互动和支持的一种全新的方式。客户和支持专业人员都注意到了这一点。 研究发现&#xff0c;高达41%的消费者更喜欢实时聊天&…