Spring中事务的隔离级别和传播机制

上一篇博客中讲解了关于事务的两种使用方式包括@Transactional的详解。

@Transactional 注解当中的三个常⻅属性:
1. rollbackFor: 异常回滚属性. 指定能够触发事务回滚的异常类型. 可以指定多个异常类型
2. Isolation: 事务的隔离级别. 默认值为 Isolation.DEFAULT
3. propagation: 事务的传播机制. 默认值为 Propagation.REQUIRED

关于第二点和第三点还没有讲解完,这一篇博客来讲解关于事务的隔离级别和传播机制。


1. 事务的隔离级别

事务有4大特性(ACID),原子性、持久性、一致性和隔离性,具体概念如下:

原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

持久性:务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatableread)和串行化(Serializable)。

其中隔离性在我之前的博客中也有讲解,建议去看看:
MySQL事务的四种隔离级别详解-CSDN博客文章浏览阅读1k次,点赞33次,收藏20次。MySQL为我们提供了不同的“隔离级别”,这样就方便使用者控制隔离级别的高低/并发程度的高低/执行效率的高低/准确性的高低。因为MySQL服务器是要给多个客户端来使用的,那么此时多个客户端之间就会同时发起事务,尤其是发起的多个事务在操作同一个数据库的同一个表的时候,这样由于“多线程”的操作就很容易引发一些“意料之外的”麻烦。如果隔离性越高,就意味着事务之间的并发程度越低,执行效率越慢,但是数据的准确性是越高的。如果隔离性越低,就意味着事务时间的并发程度越高,执行效率越快,但是数据的准确性是越低的。https://blog.csdn.net/qq_45875349/article/details/136722597我们为什么要设置隔离级别?

设置事务的隔离级别是⽤来保障多个并发事务执⾏更可控,更符合操作者预期的。

2. Spring中设置事务的隔离级别

Spring 中事务隔离级别可以通过 @Transactional 中的 isolation 属性进⾏设置,具体操作如下图所示:
在学习Spring中的事务隔离级别前,先回顾一下刚才我的博客中提到的MySQL中的隔离级别:
MySQL 事务隔离级别有 4 种
  1. READ UNCOMMITTED:读未提交,也叫未提交读,该隔离级别的事务可以看到其他事务中未提交的数据。该隔离级别因为可以读取到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此我们把该级别读取到的数据称之为脏数据,把这个问题称之为脏读。
  2. READ COMMITTED:读已提交,也叫提交读,该隔离级别的事务能读取到已经提交事务的数据。因此它不会有脏读问题。但由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同 SQL 查询中,可能会得到不同的结果,这种现象叫做不可重复读。
  3. REPEATABLE READ:可重复读,是 MySQL 的默认事务隔离级别,它能确保同一事务多次查询只的结果一致。但也会有新的问题,比如此级别的事务正在执行时,另一个事务成功的插入了某条数据,但因为它每次查询的结果都是一样的,所以会导致查询不到这条数据,自己重复插入时又失败(因为唯一约束的原因)。明明在事务中查询不到这条信息,但自己就是插入不进去,这就叫幻读(Phantom Read)。
  4. SERIALIZABLE:序列化,事务最高隔离级别,它会强制事务排序,使之不会发生冲突、从而解决了脏读、不可重复读和幻读问题,但因为执行效率低,所以真正使用的场景并不多。

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

select @@global.tx_isolation,@@tx_isolation;
Spring 事务隔离级别有 5 种
⽽ Spring 中事务隔离级别包含以下 5 种:
  • Isolation.DEFAULT:以连接的数据库的事务隔离级别为主。
  • Isolation.READ_UNCOMMITTED:读未提交,可以读取到未提交的事务,存在脏读。
  • Isolation.READ_COMMITTED:读已提交,只能读取到已经提交的事务,解决了脏读,存在不可重复读。
  • Isolation.REPEATABLE_READ:可重复读,解决了不可重复读,但存在幻读(MySQL默认级别)。
  • Isolation.SERIALIZABLE:串⾏化,可以解决所有并发问题,但性能太低。
从上述介绍可以看出,相⽐于 MySQL 的事务隔离级别,Spring 的事务隔离级别只是多了⼀个。
Spring 中事务隔离级别可以通过 @Transactional 中的 isolation 属性进⾏设置:

3. Spring事务传播机制

3.1 什么是事务的传播机制

事务传播机制就是: 多个事务方法存在调用关系时, 事务是如何在这些方法间进⾏传播的。
比如有两个⽅法A, B都被 @Transactional 修饰, A方法调用B⽅法, A方法运行时, 会开启⼀个事务. 当A调用B时, B方法本⾝也有事务, 此时B方法运行时, 是加入A的事务, 还是创建⼀个新的事务呢?
这个就涉及到了事务的传播机制!
⽐如公司流程管理
执⾏任务之前, 需要先写执⾏⽂档, 任务执⾏结束, 再写总结汇报
此时A部⻔有⼀项⼯作, 需要B部⻔的⽀援, 此时B部⻔是直接使⽤A部⻔的⽂档, 还是新建⼀个⽂档呢?

事务隔离级别解决的是多个事务同时调⽤⼀个数据库的问题  

⽽事务传播机制解决的是⼀个事务在多个节点(方法)中传递的问题:

3.2 事务的传播机制有哪些

@Transactional 注解支持事务传播机制的设置,通过 propagation 属性来指定传播行为。

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。

3.3 Spring事务传播机制演示

3.3.1 REQUIRED(默认值)

如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

比如现在我们有两个银行账户A001和A002,进行转账交易。一个转账的业务可分为两个步骤:

1.A001从自己的账户扣款;

2.A002的账户加上A001扣的款。

如果有任何一步骤失败了,都应该全部回滚。因为如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。两步操作肯定是在同一事务中。

controller代码:

package com.example.transactiondemo.controller;import com.example.transactiondemo.service.BankService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/bank")
public class BankController {@Autowiredprivate BankService bankService;@PostMapping("/transfer")@Transactional(propagation = Propagation.REQUIRED)public String transfer(@RequestParam String fromAccount, @RequestParam String toAccount, @RequestParam double amount) {//从账户A001扣钱bankService.transfer1(fromAccount, amount);//给账户A002加钱bankService.transfer2(toAccount, amount);return "Transfer successful";}
}

service代码:

package com.example.transactiondemo.service;import com.example.transactiondemo.entity.Account;
import com.example.transactiondemo.mapper.AccountMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;@Service
public class BankService {@Resourceprivate AccountMapper accountMapper;@Transactional(propagation = Propagation.REQUIRED)public void transfer1(String fromAccountNumber, double amount) {Account fromAccount = accountMapper.findByAccountNumber(fromAccountNumber);if (fromAccount == null ) {throw new IllegalArgumentException("Invalid account number");}if (fromAccount.getBalance() < amount) {throw new IllegalArgumentException("Insufficient balance in account: " + fromAccountNumber);}fromAccount.setBalance(fromAccount.getBalance() - amount);accountMapper.updateAccount(fromAccount);}@Transactional(propagation = Propagation.REQUIRED)public void transfer2(String toAccountNumber, double amount) {Account toAccount = accountMapper.findByAccountNumber(toAccountNumber);if (toAccount == null) {throw new IllegalArgumentException("Invalid account number");}toAccount.setBalance(toAccount.getBalance() + amount);accountMapper.updateAccount(toAccount);// 手动引入异常来测试事务回滚if (amount > 500) {throw new RuntimeException("Transfer amount exceeds limit, transaction will be rolled back");}}
}

注意这个手动加入的异常是伪代码,没有实际意义,为了演示效果。

Mapper代码:

package com.example.transactiondemo.mapper;import com.example.transactiondemo.entity.Account;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;@Mapper
public interface AccountMapper {Account findByAccountNumber(@Param("accountNumber") String accountNumber);void updateAccount(Account account);
}

xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.transactiondemo.mapper.AccountMapper"><select id="findByAccountNumber" resultType="com.example.transactiondemo.entity.Account">SELECT id, account_number AS accountNumber, balanceFROM accountWHERE account_number = #{accountNumber}</select><update id="updateAccount">UPDATE accountSET balance = #{balance}WHERE id = #{id}</update>
</mapper>

使用POSTMAN测试:

第一次转账100应该成功,没有触发异常都正常提交:

第二次转账600应该失败,触发了异常(手动),数据库中没有任何变化:

因为,上述操作的执行流程大概是:

其他事务传播机制的使用都大同小异,主要还是根据不同的场景来觉得使用什么类型的传播机制。


总 结

1. 通过 @Transactional(isolation = Isolation.SERIALIZABLE) 设置事务的隔离级 别. Spring 中的事务隔离级别有 5 种
2. 通过 @Transactional(propagation = Propagation.REQUIRED) 设置事务的传播机制, Spring 中的 事务传播级别有 7 种, 重点关注 REQUIRED (默认值) 和 REQUIRES_NEW

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

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

相关文章

短视频矩阵系统:高效运营,解决多账号管理难题

前言 在当下短视频风靡的时代&#xff0c;如何高效管理和运营多个短视频账号&#xff0c;成为了众多运营者面临的挑战。而今&#xff0c;一款全新的短视频矩阵系统应运而生&#xff0c;它不仅融合了AI文案生成与剪辑模式等先进功能&#xff0c;更支持多平台授权&#xff0c;助…

超分辨率重建——2022冠军RLFN网络推理测试(详细图文教程)

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…

如何用Vue3打造一个炫酷的树状图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 基于 Vue.js 的 Treemap 可视化组件 应用场景介绍 Treemap 可视化组件是一种强大的工具&#xff0c;用于以直观的方式展示分层数据。它将数据点绘制为矩形&#xff0c;其中每个矩形的大小与数据点的大小成正比…

阿里云平台创建设备及连接

使用阿里云平台创建项目&#xff0c;利用MQTT.fx软件配置相关的连接&#xff0c;在软件上完成消息的订阅与推送&#xff0c;与手机APP进行同步数据。了解MQTT相关的协议。 1.注册阿里云平台账号&#xff0c;完成实名注册&#xff01; 618创新加速季_新迁入云享5亿算力补贴-阿里…

JCR一区 | Matlab实现GAF-PCNN、GASF-CNN、GADF-CNN的多特征输入数据分类预测/故障诊断

JJCR一区 | Matlab实现GAF-PCNN、GASF-CNN、GADF-CNN的多特征输入数据分类预测/故障诊断 目录 JJCR一区 | Matlab实现GAF-PCNN、GASF-CNN、GADF-CNN的多特征输入数据分类预测/故障诊断分类效果格拉姆矩阵图GAF-PCNNGASF-CNNGADF-CNN 基本介绍程序设计参考资料 分类效果 格拉姆…

【网络编程开发】16.域名解析与http服务器实现原理

16.域名解析与http服务器实现原理 文章目录 16.域名解析与http服务器实现原理gethostbyname 函数HTTP的操作过程实现httphome.htmlhttp-head.txtserver.c gethostbyname 函数 原型&#xff1a; #include <netdb.h> struct hostent *gethostbyname(const char *hostname);…

技巧|手机上看SwanLab实验的两种方法

什么是SwanLab? SwanLab是一个深度学习实验管理与训练可视化工具&#xff0c;由西安电子科技大学创业团队打造&#xff0c;融合了Weights & Biases与Tensorboard的特点&#xff0c;可以记录整个实验的超参数、指标、训练环境、Python版本等&#xff0c;并可视化图表&…

google chrome浏览器安装crx插件Jam

先上一张图&#xff1a; Jam是bug报告生成插件 1、在地址栏中输入chrome://extensions/&#xff0c;然后回车。 2、将下载好的crx插件&#xff0c;直接拖到里面就可以完成安装工作了。 3、测试了一下jam插件&#xff0c;发现直接没有响应。 4、点击【移除】直接可以删除插件…

这四个有意思的工具,很香

提醒英雄 提醒英雄应用是一款能够帮助用户彻底解决健忘症的应用程序。该应用创建的事项会完全同步到通知中心&#xff0c;并且持续保持在锁屏界面上&#xff0c;只要打开手机&#xff0c;用户就会看到之前设置的提醒事项。这种设计确保了用户在任何时候都能及时收到提醒&#…

YOLOv10改进 | 注意力篇 | YOLOv10引入Polarized Self-Attention注意力机制

1. Polarized Self-Attention介绍 1.1 摘要:像素级回归可能是细粒度计算机视觉任务中最常见的问题,例如估计关键点热图和分割掩模。 这些回归问题非常具有挑战性,特别是因为它们需要在低计算开销的情况下对高分辨率输入/输出的长期依赖性进行建模,以估计高度非线性的像素语…

JavaFX DatePicker

JavaFX DatePicker允许从给定日历中选择一天。DatePicker控件包含一个带有日期字段和日期选择器的组合框。JavaFX DatePicker控件使用JDK8日期时间API。 import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.DatePicker; import j…

004-配置交换机ssh远程登录

配置交换机ssh远程登录 注意事项 要远程的本机电脑必须与该交换机在同一个网段&#xff0c;以下实验在172.16.12段下模拟&#xff0c;本地ip设置为172.16.12.10&#xff0c;交换机的ip设置为172.16.12.254 将密码设置为明文&#xff08;simple&#xff09;是不安全的&#x…

C++实时检测耳机的插入与拔出(附源码)

目录 1、实现继承于IMMNotificationClient接口类的CMMNotificationClient类,实时感知音频设备变化的通知事件 2、在CMMNotificationClient的构造函数中初始化多媒体设备COM接口,设置回调类指针 3、通过获取音频设备接口下外设的KSJACK_DESCRIPTION 信息判断耳机的连接状态…

猫头虎分享已解决Bug || 前端领域技术问题解析

原创作者&#xff1a; 猫头虎 作者微信号&#xff1a; Libin9iOak 作者公众号&#xff1a; 猫头虎技术团队 更新日期&#xff1a; 2024年6月6日 博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &…

从老花眼开始

三年前&#xff0c;博主的的火眼金睛开始老花了&#xff0c;表现就是看近处看不清了。人眼对可视距离的标准可以定义为&#xff1a;看手机为近距离&#xff0c;看电脑为中距离&#xff0c;看电视为中距离&#xff0c;看红绿灯为远距离。老花眼就是戴近视眼镜直接看手机看不清了…

聆思CSK6大模型+AI交互多模态开源SDK介绍

视觉语音大模型 AI 开发套件( CSK6-MIX )是围绕 CSK6011A 芯片设计的具备丰富语音图像功能与硬件外设的开发板&#xff0c;采用具备丰富组件生态的 Zephyr RTOS作为操作系统&#xff0c;官方提供了十几种开源SDK&#xff0c;包含大模型语音交互、大模型拍照识图、文生图、人脸识…

如何在不同的操作系统中查看路由器的IP地址?这里有详细步骤

如果你曾经需要访问路由器的设置页面来进行一些配置更改,你知道你需要路由器的IP地址才能访问。如果你忘记了这个IP地址是什么,下面是如何在几乎所有平台上找到它的。 为什么路由器的IP很有用 在网络世界中,默认网关是一个IP地址,当流量被发送到当前网络之外的目的地时,…

国能数智集团侧交付中心经理曲明志受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 国能数智科技开发&#xff08;北京&#xff09;有限公司智能电力业务部总监、集团侧交付中心经理、公司项目经理协会会长曲明志先生受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“运营类项目建设经验分享”。大会将于6月…

工业边缘计算网关在机械制造企业中的应用-天拓四方

随着信息技术的不断发展&#xff0c;工业领域对数据处理和分析的需求日益增长。工业边缘计算网关作为一种新型技术&#xff0c;正逐渐成为工业数字化转型的关键驱动力。本文将通过一个具体案例阐述工业边缘计算网关在工业中的应用&#xff0c;以及其为工业生产带来的显著效益。…

Anvil Empires/铁砧帝国操作没反应、频繁掉线怎么办?

Anvil Empires是一款多人在线游戏&#xff0c;且规模非常大&#xff01;玩家需要在持续的在线世界中与成千上万的玩家一起发动战争。目前自定义服务器技术可以使多达 1000 名玩家能够在大规模的实时战斗&#xff0c;且战斗是由玩家在开放世界沙盒中有机地煽动的&#xff0c;所以…