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

Spring事务和事务传播机制(2)

前言🍭

❤️❤️❤️SSM专栏更新中,各位大佬觉得写得不错,支持一下,感谢了!❤️❤️❤️

Spring + Spring MVC + MyBatis_冷兮雪的博客-CSDN博客

在Spring框架中,事务管理是一种用于维护数据库操作的一致性和完整性的机制。Spring事务管理提供了灵活的方式来处理事务,包括事务的创建、提交、回滚以及事务的传播行为。

书接上回:Spring事务和事务传播机制(1)_热爱编程的林兮的博客-CSDN博客 

2、Spring 中设置事务隔离级别🍉

Spring 中事务隔离级别可以通过 @Transactional 中的 isolation 属性进行设置,具体操作如下图所示:

Ⅰ、MySQL 事务隔离级别有 4 种 🍓

1、READ UNCOMMITTED: 读未提交,也叫未提交读,该隔离级别的事务可以看到其他事务中未提交的数据。该隔离级别因为可以读取到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此我们把该级别读取到的数据称之为脏数据,把这个问题称之为脏读

2、READ COMMITTED: 读已提交,也叫提交读,该隔离级别的事务能读取到已经提交事务的数据因此它不会有脏读问题。但由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同 SQL查询中,可能会得到不同的结果,这种现象叫做不可重复读。
3、REPEATABLE READ:可重复读是MySQL 的默认事务隔离级别,它能确保同一事务多次查询的结果一致。但也会有新的问题,比如此级别的事务正在执行时,另一个事务成功的插入了某条数据,但因为它每次查询的结果都是一样的,所以会导致查询不到这条数据,自己重复插入时又失败(因为唯一约束的原因)。明明在事务中查询不到这条信息,但自己就是插入不进去,这就叫幻读(Phantom Read)。
4、SERIALIZABLE: 序列化,事务最高隔离级别,它会强制事务排序,使之不会发生冲突,从而解决了脏读、不可重复读和幻读问题,但因为执行效率低,所以真正使用的场景并不多。

事务隔离级别脏读不可重复读幻读
读未提交(READ UNCOMMITTED) 
读已提交(READ COMMITTED)×
可重复读(REPEATABLE READ)××
串行化(SERIALIZABLE)×××
  • 脏读:一个事务读取到了另一个事务修改的数据之后,后一个事务又进行了回滚操作,从而导致第一个事务读取的数据是错误的。
  • 不可重复读:一个事务两次查询得到的结果不同,因为在两次查询中间,有另一个事务把数据修0改了。
  • 幻读:一个事务两次查询中得到的结果集不同,因为在两次查询中另一个事务有新增了一部分数据。

在数据库中通过以下 SQL 查询全局事务隔离级别和当前连接的事务隔离级别:

select @@global.tx_isolation,@@tx_isolation;
以上 SQL 的执⾏结果如下:

Ⅱ、Spring 事务隔离级别有 5 种🍓

而Spring 中事务隔离级别包含以下 5 种:

  1. Isolation.DEFAULT:以连接的数据库的事务隔离级别为主。
  2. Isolation.READ_UNCOMMITTED:读未提交,可以读取到未提交的事务,存在脏读。
  3. Isolation.READ_COMMITTED:读已提交,只能读取到已经提交的事务,解决了脏读,存在不可重复读。
  4. Isolation.REPEATABLE_READ:可重复读,解决了不可重复读,但存在幻读(MySQL默认级别)。
  5. Isolation.SERIALIZABLE:串行化,可以解决所有并发问题,但性能太低。

从上述介绍可以看出,相⽐于 MySQL 的事务隔离级别,Spring 的事务隔离级别只是多了一个

Isolation.DEFAULT(以数据库的全局事务隔离级别为主)。

Spring 中事务隔离级别只需要设置 @Transactional ⾥的 isolation 属性即可,具体实现代码如下

@RequestMapping("/save")@Transactional(isolation = Isolation.SERIALIZABLE)public Object save(UserInfo user) {// 业务实现}

四、Spring 事务传播机制🍭

1、事务传播机制是什么?🍉

Spring 事务传播机制定义了多个包含了事务的方法,相互调用时,事务是如何在这些方法间进行传递的。

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

事务隔离级别是保证多个并发事务执行的可控性的(稳定性的),而事务传播机制是保证⼀个事务在多个调用方法间的可控性的(稳定性的)。

例子:像新冠病毒⼀样,它有不同的隔离方式(酒店隔离还是居家隔离),是为了保证疫情可控,然而在每个人的隔离过程中,会有很多个执行的环节,比如酒店隔离,需要负责人员运送、物品运送、消杀原生活区域、定时核算检查和定时送餐等很多环节,而事务传播机制就是保证⼀个事务在传递过程中是可靠性的,回到本身案例中就是保证每个人在隔离的过程中可控的。

事务隔离级别解决的是多个事务同时调用⼀个数据库的问题,如下图所示:

事务传播机制解决的是⼀个事务在多个节点(方法)中传递的问题,如下图所示:

3、事务传播机制有哪些?🍉

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 类:

以情侣关系为例来理解以上分类:

4、Spring 事务传播机制使用和各种场景演示🍉

Ⅰ、支持当前事务(REQUIRED)🍓

以下代码实现中,先开启事务先成功插入一条用户数据,然后再执行日志报错,而在日志报错是发生了异常,观察 propagation = Propagation.REQUIRED 的执行结果。

@Autowiredprivate UserService userService;
@Autowiredprivate LogService logService;@Transactional// 声明式事务(自动提交)@RequestMapping("/insert")public Integer insert(UserInfo userInfo) {// 非空效验if (userInfo == null || !StringUtils.hasLength(userInfo.getUsername()) ||!StringUtils.hasLength(userInfo.getPassword())) {return 0;}// 添加用户int result = userService.add(userInfo);if (result>0){//日志logService.add();}/*try {int num = 10 / 0;} catch (Exception e) {System.out.println(e.getMessage());*//*throw e;*//*TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}*/return result;}

UserService 实现代码如下:

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@Transactional(propagation = Propagation.REQUIRED)public Integer add(UserInfo userInfo) {int result = userMapper.add(userInfo);System.out.println("用户添加:" + result);return result;}}
LogService 实现代码如下:
@RestController
public class LogService {//捣乱,设置一个算数异常@Transactional(propagation = Propagation.REQUIRED)public int add() {int num = 10 / 0;return 1;}
}

执行结果:程序报错,数据库没有插入任何数据。

 执行了SQL语句,都是数据库中没有添加新用户,事务回滚了

 执行流程描述

  1. UserService 中的保存方法正常执行完成。
  2. LogService 保存日志程序报错,因为使用的是 Controller 中的事务,所以整个事务回滚。
  3. 数据库中没有插入任何数据,也就是步骤1中的用户插入方法也回滚了。

Ⅱ、不支持当前事务(REQUIRES_NEW)🍓

UserController 类中的代码不变,将添加用户和添加日志的方法修改为 REQUIRES_NEW 不支持当前事务,重新创建事务,观察执行结果:

@RestControllerpublic class UserController {@Resourceprivate UserService userService;@Resourceprivate LogService logService;@RequestMapping("/save")@Transactional(propagation = Propagation.REQUIRED)public Object save(UserInfo userInfo) {// 插⼊⽤户操作userService.save(userInfo);// 插⼊⽇志logService.saveLog("⽤户插⼊:" + userInfo.getName());return true;}}

UserService 实现代码如下:

@Servicepublic class UserService {@Resourceprivate UserMapper userMapper;@Transactional(propagation = Propagation.REQUIRED)public int save(UserInfo userInfo) {System.out.println("执⾏ save ⽅法.");return userMapper.save(userInfo);}}

LogService 实现代码如下:

@Servicepublic class LogService {@Transactional(propagation = Propagation.REQUIRED)public int saveLog(String content) {// 出现异常int i = 10 / 0;return 1;}}

程序执行结果:User 表中成功插入了数据,LogService 保存日志程序报错,但没影响 UserController 中的事务。

Ⅲ、不支持当前事务,NEVER 抛异常🍓

UserController 实现代码:

@RequestMapping("/save")@Transactionalpublic Object save(UserInfo userInfo) {// 插⼊⽤户操作userService.save(userInfo);return true;}

UserService 实现代码:

@Transactional(propagation = Propagation.NEVER)public int save(UserInfo userInfo) {System.out.println("执⾏ save ⽅法.");return userMapper.save(userInfo);}

程序执行报错,用户表未添加任何数据。

Ⅳ、NESTED 嵌套事务🍓

UserController 实现代码如下:

@RequestMapping("/save")@Transactionalpublic Object save(UserInfo userInfo) {// 插⼊⽤户操作userService.save(userInfo);return true}
UserService 实现代码如下:
@Transactional(propagation = Propagation.NESTED)public int save(UserInfo userInfo) {int result = userMapper.save(userInfo);System.out.println("执⾏ save ⽅法.");// 插⼊⽇志logService.saveLog("⽤户插⼊:" + userInfo.getName());return result;}
LogService 实现代码如下:
@Transactional(propagation = Propagation.NESTED)public int saveLog(String content) {// 出现异常int i = 10 / 0;return 1;}

最终执行结果,用户表和日志表都没有添加任何数据。

嵌套事务和加入事务有什么区别🍓

  1. 整个事务如果全部执行成功,二者的结果是⼀样的。

  2. 如果事务执行到一半失败了,那么加入事务整个事务会全部回滚;而嵌套事务会局部回滚,不会影响上一个方法中执行的结果

相关文章:

Spring事务和事务传播机制(2)

前言🍭 ❤️❤️❤️SSM专栏更新中,各位大佬觉得写得不错,支持一下,感谢了!❤️❤️❤️ Spring Spring MVC MyBatis_冷兮雪的博客-CSDN博客 在Spring框架中,事务管理是一种用于维护数据库操作的一致性和…...

计算机视觉 -- 图像分割

文章目录 1. 图像分割2. FCN2.1 语义分割– FCN (Fully Convolutional Networks)2.2 FCN--deconv2.3 Unpool2.4 拓展–DeconvNet 3. 实例分割3.1 实例分割--Mask R-CNN3.2 Mask R-CNN3.3 Faster R-CNN与 Mask R-CNN3.4 Mask R-CNN:Resnet1013…...

ubuntu18.04复现yolo v8之CUDA与pytorch版本问题以及多CUDA版本安装及切换

最近在复现yolo v8的程序,特记录一下过程 环境:ubuntu18.04ros melodic 小知识:GPU并行计算能力高于CPU—B站UP主说的 Ubuntu可以安装多个版本的CUDA。如果某个程序的Pyorch需要不同版本的CUDA,不必删除之前的CUDA,…...

Redis三种模式——主从复制,哨兵模式,集群

目录 一、主从复制 1.1主从复制的概念 1.2Redis主从复制作用 1.2.1数据冗余 1.2.2故障恢复 1.2.3负载均衡 1.2.4高可用基石 1.3Redis主从复制流程 1.4部署Redis 主从复制 1.4.1.环境部署 1.4.2.所有服务器都先关闭防火墙 1.4.3.所有服务器都安装Redis 1.4.4修改Master主节点R…...

mysql8.0.31新增只读远程普通用户

在 MySQL 8.0.31 中,可以通过以下步骤新增只读远程普通用户: 1、使用 root 用户登录 MySQL 数据库。 mysql -u root -p 2、创建用户: CREATE USER username% IDENTIFIED WITH mysql_native_password BY password ; 其中,username…...

揭开路由协议隐藏的风险

路由协议在互联网和基于其的服务的运行中发挥着至关重要的作用。然而,许多这些协议的开发都没有考虑到安全问题。 例如,边界网关协议 (BGP) 最初并未考虑对等点之间发生攻击的可能性。过去几十年来,BGP 中的起源和路径验证已投入了大量工作。…...

图片因固定宽高被拉伸了?object-fit:一个神奇的属性

一、问题产生的场景 近期在完成项目开发时,测试人员针对漫画长图上传后的展示提出了一个界面优化的点,因为其特点是长,但是我们展示图片的区域是固定的,如果我们按照正常思路将图片的宽高写死,确实占位大小的问题解决了…...

客户案例:中圣科技—CAC2.0防范盗号威胁,加固安全防线

客户背景 中圣科技(江苏)股份有限公司(以下简称“中圣科技”),是一家以技术研发为驱动,以清洁能源核心成套装备和节能环保工程服务为支撑的科技创新型企业。其以南京为核心运营基地,与当地政府…...

pandas数据分析40——读取 excel 合并单元格的表头

案例背景 真的很容易疯....上班的单位的表格都是不同的人做的,所以就会出现各种合并单元格的情况,要知道我们用pandas读取数据最怕合并单元格了,因为没规律...可能前几列没合并,后面几列又合并了....而且pandas对于索引很严格&am…...

Java后端开发面试题——微服务篇总结

Spring Cloud 5大组件有哪些? 随着SpringCloudAlibba在国内兴起 , 我们项目中使用了一些阿里巴巴的组件 注册中心/配置中心 Nacos 负载均衡 Ribbon 服务调用 Feign 服务保护 sentinel 服务网关 Gateway Ribbon负载均衡策略有哪些 ? RoundRobinRule&…...

第十一章MyBatis查询专题

返回单个Car 返回单个可以直接用Car接收返回参数 Car carCarMapper.getOne(100);返回多个Car 返回多个可以直接用List接收返回参数 List<Car> carCarMapper.getAll();用一个对象无法接受返回多个参数&#xff0c;用list可以接收返回一个参数 返回Map 如果没有合适的…...

测试驱动开发(TDD)

测试驱动开发&#xff08;TDD&#xff09; 本篇文章简单叙述一下什么是测试驱动开发&#xff0c;以及怎么进行测试驱动开发&#xff01; TDD &#xff08;Test Driven Development&#xff09;&#xff1a;&#xff08;源于极限编程&#xff08;XP&#xff09;&#xff09;在不…...

深度学习|CNN卷积神经网络

CNN卷积神经网络 解决的问题人类的视觉原理原理卷积层——提取特征池化层——数据降维全连接层——输出结果 应用图像处理自然语言处理 解决的问题 在CNN没有出现前&#xff0c;图像对人工智能来说非常难处理。 主要原因&#xff1a; 图像要处理的数据量太大了。图像由像素组…...

【洁洁送书第五期】为什么我们要了解可观测性工程

导读 可观测性已成为一个热门话题&#xff0c;并广受关注。随着它的普及&#xff0c;“可观测性”不幸被误作“监控”或“系统遥测”的同义词。可观测性是软件系统的一个特征。而且&#xff0c;只有当团队采用新的实践进行持续开发时&#xff0c;才能在生产软件系统中有效利用这…...

将vue项目通过electron打包成windows可执行程序

将vue项目打包成windows可执行程序 1、准备好dist将整个项目打包 npm run build2、安装electron依赖 npm install electron --save-dev npm install electron-packager --save-dev"electron": "^13.1.4", "electron-packager": "^15.2.0…...

【0基础入门Python Web笔记】三、python 之函数以及常用内置函数

三、python 之函数以及常用内置函数 函数函数定义函数调用函数参数返回值 常用内置函数input()函数range()函数其它 更多实战项目可进入下方官网 函数 函数是一种用于封装可重复使用代码块的工具&#xff0c;能够将一系列操作组织成一个逻辑单元。 函数定义 在Python中&…...

相交链表00

题目链接 相交链表 题目描述 注意点 保证 整个链式结构中不存在环函数返回结果后&#xff0c;链表必须 保持其原始结构如果 listA 和 listB 没有交点&#xff0c;intersectVal 为 0 解答思路 两个链表从头开始遍历&#xff0c;如果其是在同一个位置处相交&#xff0c;则在…...

怎样压缩mp4视频大小?

怎样压缩mp4视频大小&#xff1f;由于视频文件的体积通常比其他类型的文件更大&#xff0c;因此它们需要更多的存储空间来保存。但是&#xff0c;如果我们的设备、应用程序或平台不支持某些视频格式或分辨率&#xff0c;或者我们没有足够的存储空间来容纳这些大型视频文件&…...

ubuntu20.04 安装使用 Indemind 双目相机

1、先按照官方wiki搭建环境 Ubuntu 安装 — IMSEE SDK 1.4.2 文档&#xff08;ubuntu20使用官网会报错&#xff0c;可以参考我下面的步骤&#xff09; 1.1、获取代码 sudo apt-get install git git clone https://github.com/indemind/IMSEE-SDK.git 1.2、准备依赖 cd <…...

一文读懂设备管理系统:是什么、谁需要、怎样选

工业的迅猛发展让人类向前迈出了史无前例的步伐&#xff0c;工业4.0将我们又带入了一个信息化技术促进工业变革的新时代——智能化时代。一台台机器设备是工业发展史上必不可少的参与者&#xff0c;但企业对设备的管理存在种种痛点&#xff0c;比如生产设备多&#xff0c;但备件…...

删除链表的中间节点

题目&#xff1a; 示例&#xff1a; 思路&#xff1a; 这个题类似于寻找链表中间的数字&#xff0c;slow和fast都指向head&#xff0c;slow走一步&#xff0c;fast走两步&#xff0c;也许你会有疑问&#xff0c;节点数的奇偶不考虑吗&#xff1f;while执行条件写成fast&&…...

Q/GDW 1597-2015《国家电网公司应用软件系统通用安全要求》

电力安全测试报告 电力行业检测标准 随着信息技术的快速发展和广泛应用&#xff0c;应用软件系统已成为企业信息化建设中不可或缺的重要组成部分。然而&#xff0c;应用软件系统的安全问题也随之而来&#xff0c;给企业和用户带来了潜在的风险和威胁。为了提高应用软件系统的…...

【前端从0开始】CSS——12、光标属性

光标属性 cursor 属性规定要显示的光标的类型&#xff08;形状&#xff09;。 该属性定义了鼠标指针放在一个元素边界范围内时所用的光标形状&#xff08;不过 CSS2.1 没有定义由哪个边界确定这个范围&#xff09;。 属性名效果crosshair精确定位“十”字形pointer“小手”形…...

文件四剑客

目录 前言 一、正则表达式 二、grep 三、find 四、sed 五、awk 前言 文件四剑客是指在计算机领域中常用的四个命令行工具&#xff0c;包括awk、find、grep和sed。它们在处理文本文件和搜索文件时非常强大和实用。 1. awk是一种强大的文本处理工具&#xff0c;它允许用户根据指…...

使用lambda表达式提取共用代码使其更加简洁

1、在开发预下单接口访问并发问题出现需要加锁代码如下 RLock lock redissonClient.getLock(String.format(appointmentKey, activityId, studentId));try {boolean tryLock lock.tryLock(10, 20, TimeUnit.SECONDS);if (tryLock) {AppointmentMallOrderInfoDTO appointmentM…...

【八股】2023秋招八股复习笔记3(智力题 非技术题50道)

文章目录 1、智力题赛⻢问题烧绳⼦问题找出最重球问题药丸问题有两个杯⼦&#xff0c;囚犯问题⽣孩⼦问题赢汽⻋问题卡牌问题拿硬币问题量⽔问题聚会问题数字游戏问题艾滋病问题找出变质药问题毒药问题分盐问题弹球问题病狗问题⽕⻋运煤问题分苹果问题分⾦条问题搬⾹蕉问题舀酒…...

服务器卡顿如何排查?

服务器网络卡&#xff0c;一般情况下&#xff0c;请先检查您服务器的使用情况。 1.CPU使用率是否大于50%。 2.网络使用率是否过高。 3.内存使用率是否过高。 如果出现上述情况&#xff0c;则表明您的服务器或网络无法承载您目前的服务&#xff0c;请联系技术人员调整您的资…...

设计模式——开闭原则

文章目录 基本介绍看下面一段代码方式 1 的优缺点改进的思路分析 基本介绍 开闭原则&#xff08;Open Closed Principle&#xff09;是编程中最基础、最重要的设计原则 一个软件实体如类&#xff0c;模块和函数应该对扩展开放(对提供方)&#xff0c;对修改关闭(对使用方)。用抽…...

服务器能运行什么应用

服务器能运行什么应用 服务器是一种应用范围很广的网络技术产品&#xff0c;它在影视、视频以及医疗和金融等多个领域&#xff0c;都可以发挥使用价值&#xff0c;那么服务器能运行什么应用?大家跟着壹基比小鑫一起来了解吧&#xff01; 服务器的作用是什么&#xff1f; 服…...

Linux TCP协议

传输层的协议主要有三个&#xff1a;TCP协议&#xff08;可靠&#xff09;、UDP协议&#xff08;不可靠&#xff09;和SCPT协议&#xff08;不可靠&#xff09;。 一、TCP协议的概念 TCP协议也称传输控制协议&#xff0c;是一种可靠的、面向连接的、基于字节流的传输层通信协…...