【Spring Boot】掌握 Spring 事务:隔离级别与传播机制解读与应用

news2025/3/1 10:32:48

前言

???本期讲解关于spring 事务传播机制介绍~~~

??感兴趣的小伙伴看一看小编主页:-CSDN博客

?? 你的点赞就是小编不断更新的最大动力

??那么废话不多说直接开整吧~~

目录

???1.事务的隔离级别

??1.1MySQL事务隔离级别

??1.2Spring事务隔离级别

???2.Spring事务传播机制

??2.1什么是事务的传播机制

??2.2事务隔离与传播的区别

??2.3事务的传播机制

??2.4事务传播机制代码演示

2.4.1REQUIRED

?2.4.2REQUIRES_NEW

2.4.3NEVER

2.4.4NESTED

??2.5NESTED和REQUIRED 区别

???3.总结

**??**1.事务的隔离级别

??1.1MySQL事务隔离级别

读未提交(READ UNCOMMITTED): 读未提交, 也叫未提交读. 该隔离级别的事务可以看到其他事务中未提交的数据.

因为其他事务未提交的数据可能会发回滚, 但是该隔离级别却可以读到, 我们把该级别读到的数据称之为脏数据, 这个问题称之为脏读.(就是一个事务还没有写完,另一个事务就在读了)

读提交(READ COMMITTED): 读已提交, 也叫提交读. 该隔离级别的事务能读取到已经提交事务的数据

该隔离级别不会有脏读的问题.但由于在事务的执中可以读取到其他事务提交的结果, 所以在不同时间的相同 SQL 查询可能会得到不同的结果, 这种现象叫做不可重复读

(大致就是,事务A在写完后,B读了之后,A又再次修改了,那么B再次读之后,就会发现两次的结果不一样)

可重复读(REPEATABLE READ): 事务不会读到其他事务对已有数据的修改, 即使其他事务已提交. 也就可以确保同事务多次查询的结果致, 但是其他事务新插的数据, 是可以感知到的. 这也就引发了幻读问题. 可重复读, 是 MySQL 的默认事务隔离级别.

如此级别的事务正在执时, 另个事务成功的插了某条数据, 但因为它每次查询的结果都是样的, 所以会导致查询不到这条数据, 重复插时失败(因为唯约束的原因). 明明在事务中查询不到这条信息,但就是插不进去, 这个现象叫幻读

串化(SERIALIZABLE): 序列化, 事务最隔离级别. 它会强制事务排序, 使之不会发冲突, 从解决了脏读, 不可重复读和幻读问题, 但因为执效率低, 所以真正使的场景并不多

??1.2Spring事务隔离级别

Spring 中事务隔离级别有5 种:

1. Isolation.DEFAULT : 以连接的数据库的事务隔离级别为主.
2. Isolation.READ_UNCOMMITTED : 读未提交, 对应SQL标准中 READ UNCOMMITTED
3. Isolation.READ_COMMITTED : 读已提交,对应SQL标准中 READ COMMITTED
4. Isolation.REPEATABLE_READ : 可重复读, 对应SQL标准中 REPEATABLE READ
5. Isolation.SERIALIZABLE : 串化, 对应SQL标准中 SERIALIZABLE

设置事务的隔离级别代码如下:

 @Transactional(rollbackFor = Exception.class, isolation = Isolation.DEFAULT)
    //设置所有回滚异常类型
    @RequestMapping("/r7")
    public Boolean r7(String userName, String password) throws IOException {
        Integer result = userService.registUser(userName, password);
        System.out.println("插入用户表, result: "+ result);
        if (true){
            throw new IOException();
        }

        return true;
    }

解释:

在代码中,注解里的参数rollbackfor指定所有异常都需要进行回滚,然后isolation指定是与数据库的事务隔离级别是一致的,那么这里的spring事务的隔离级别就是可重复读;

**??**2.Spring事务传播机制

??2.1什么是事务的传播机制

事务传播机制就是: 多个事务法存在调关系时, 事务是如何在这些法间进传播的

就比如,两个方法,都被transaction修饰了,假如这里的两个方法存在调用的关系,那么这里的事务是如何进行传播的,是使用A的事务,还是使用B的事务呢?

??2.2事务隔离与传播的区别

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

如下图:

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

??2.3事务的传播机制

@Transactional 注解持事务传播机制的设置, 通过 propagation 属性来指定传播为.
Spring 事务传播机制有以下 7 种:

B是被调用的一方(service),A是调用的一方(controller)

1. Propagation.REQUIRED : 默认的事务传播级别. 如果当前存在事务, 则加该事务. 如果当前没
有事务, 则创建个新的事务.)

A有事务,B就直接使用A的事务,如果A没有事务,B创建一个事务

2. Propagation.SUPPORTS : 如果当前存在事务, 则加该事务. 如果当前没有事务, 则以事务的式继续运.

A有事务,B就直接使用A的事务,如果A没有事务,B以非事务的方式进行运行

**3. Propagation.MANDATORY 😗*强制性. 如果当前存在事务, 则加该事务. 如果当前没有事务, 则
抛出异常.

A有事务,B就直接使用A的事务,如果A没有事务,那么就直接抛出异常

4. Propagation.REQUIRES_NEW : 创建个新的事务. 如果当前存在事务, 则把当前事务挂起. 也
就是说不管外部法是否开启事务, Propagation.REQUIRES_NEW 修饰的内部法都会新开
启的事务, 且开启的事务相互独, 互不扰.

就是不管A有无事务,B都创建新的事务

5. Propagation.NOT_SUPPORTED : 以事务式运, 如果当前存在事务, 则把当前事务挂起(不).

就是不管A有无事务,B都直接以非事务的方式进行运行

6. Propagation.NEVER : 以事务式运, 如果当前存在事务, 则抛出异常

如果A事务存在,那么就直接抛出异常

7. Propagation.NESTED : 如果当前存在事务, 则创建个事务作为当前事务的嵌套事务来运.
如果当前没有事务, 则该取值等价于 PROPAGATION_REQUIRED

没有事务就创建事务,有的话就干点其他的事情

??2.4事务传播机制代码演示
2.4.1REQUIRED

controller控制层,代表的A

@RequestMapping("/user")
@RestController
public class UserController2 {
    @Autowired
    private UserService userService;
    @Autowired
    private LogService logService;

    @Transactional(propagation = Propagation.REQUIRED)
    @RequestMapping("/p1")
    public String r3(String name, String password) {
        //??注册
        userService.registUser(name, password);
        //记录操作?志
        logService.insertLog(name, "??注册");
        return "p1";
    }
}

其余两个service:

登录日志打印:

@Service
public class LogService {
    @Autowired
    private LogInfoMapper logInfoMapper;
    @Transactional(propagation = Propagation.REQUIRED)
    public void insertLog(String userName,String op){

        logInfoMapper.insert(userName,"用户注册");
        int a=10/0;
    }
}

user登录:

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

    @Transactional(propagation = Propagation.REQUIRED)
    public Integer registUser(String userName, String password) {

        Integer result = userInfoMapper.insert(userName, password);

        return result;

    }
}

输出情况,打印的日志如下:

1. p1 法开始事务
2. 注册, 插条数据 (执成功) (和p1 使同个事务)
3. 记录操作志, 插条数据(出现异常, 执失败) (和p1 使同个事务)
4. 因为步骤3出现异常, 事务回滚. 步骤2和3使同个事务, 所以步骤2的数据也回滚了.

2.4.2REQUIRES_NEW

我们将这里的两个service层改成REQUIRES_NEW

这里的其中一个事务进行了提交;

另一个代码存在算数异常的就没有进行提交

这里就是单独创建了自己的事务,这里的两个service层创建的两个事务就不会相互影响,所以其中一个提交,另一个进行了回滚的操作;

2.4.3NEVER

我们将其中一个代码传播机制改变

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

    @Transactional(propagation = Propagation.NEVER)
    public Integer registUser(String userName, String password) {

        Integer result = userInfoMapper.insert(userName, password);

        return result;

    }
}

输出的日志如下所示:

那么这里可以看到报错信息就是A调用层存在事务,导致报错;

2.4.4NESTED

将上述UserService 和LogService 中相关法事务传播机制改为 Propagation.NESTED

小编这里就不演示代码了,大家可以自己去试一试;

打印日志如下:

由于是嵌套事务, LogService 出现异常之后, 往上找调它的法和事务, 所以注册也失败
了.最终结果是两个数据都没有添加
p1事务可以认为是事务, 嵌套事务是事务. 事务出现异常, 事务也会回滚, 事务出现异常, 如果不进处理, 也会导致事务回滚(可以认为是REQUIRED,但是不完全是

??2.5NESTED和REQUIRED 区别

我们知道,当两个方法不存在问题时,这里的两种传播机制是没有啥区别的,但是当出现问题时,我们可以发现情况如上图所示,但是真的没有区别吗?答案是否定的;

@Service
public class LogService {
    @Autowired
    private LogInfoMapper logInfoMapper;
    @Transactional(propagation = Propagation.NESTED)
    public void insertLog(String userName,String op){
        try {
            int a=10/0;
        }catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }

        logInfoMapper.insert(userName,"用户注册");   
    }
}

重新运程序, 发现表数据添加成功, 志表添加失败.


LogService 中的事务已经回滚, 但是嵌套事务不会回滚嵌套之前的事务, 也就是说嵌套事务可以实
现部分事务回滚

但是对于REQUIRED 如果回滚就是回滚所有事务, 不能实现部分事务的回滚. (因为属于同个事务)

嵌套事务之所以能够实现部分事务的回滚, 是因为事务中有个保存点(savepoint)的概念, 嵌套事务进之后相当于新建了个保存点, 滚回时只回滚到当前保存点.

这里是小编的理解,大家有问题或者质疑可以私信我哟~~~

**??**3.总结

**???**本期讲解了关于MySQL事务的隔离级别回顾,以及spring的事务隔离级别以及事务传播机制,分别从概念和代码进行了演示~~~

???~~~~最后希望与诸君共勉,共同进步!!!


???以上就是本期内容了, 感兴趣的话,就关注小编吧。

???期待你的关注~~~

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

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

相关文章

PySide(PyQT)重新定义contextMenuEvent()实现鼠标右键弹出菜单

在 PySide中,contextMenuEvent() 是 QWidget 类(以及继承自它的所有子类)的一个事件处理方法,主要用于处理上下文菜单事件,也就是当用户在控件上右键点击时触发的事件。 • 通过重新定义contextMenuEvent()来实现自定…

Redis 持久化方式:RDB(Redis Database)和 AOF(Append Only File)

本部分内容是关于博主在学习 Redis 时关于持久化部分的记录,介绍了 RDB 和 AOF 两种持久化方式,详细介绍了持久化的原理、配置、使用方式、优缺点和使用场景。并对两种持久化方式做了对比。文章最后介绍了 Redis 持久化的意义并与其他常见的缓存技术做了…

数据库测试

TPCH 22条SQL语句分析 - xibuhaohao - 博客园 TPCH模型规范、测试说明及22条语句 - zhjh256 - 博客园 TPC-DS 性能比较:TiDB 与 Impala-PingCAP | 平凯星辰 揭秘Oracle TPC-H性能优化:如何提升数据库查询速度,揭秘实战技巧与挑战 引言 T…

< 自用文儿 > Gobuster 暴力扫描工具与 SecLists 安全测试词表集合

Ethice 道德问题 GFW 的保护下,很多的设备操作系统是停留在更老的版本,应用软件也是,因此很多的漏洞没有被修复。通讯没有使用加密,例如网页没有使用 HTTPS 网站很多。几乎是半裸的在网络上等着被食。 不做恶是下限。 环境&…

关于网页地图的坐标系

EPSG:4326地理坐标系 和 EPSG:3857Web 墨卡托投影 EPSG:4326 定义:EPSG:4326 是基于 WGS84 椭球的地理坐标系,使用经度(Longitude)和纬度(Latitude)表示地球上的位置。特点: 经度范围为 -180 …

华为云之使用鲲鹏弹性云服务器部署Node.js环境【玩转华为云】

华为云之使用鲲鹏弹性云服务器部署Node.js环境【玩转华为云】 一、本次实践介绍1.1 实践环境简介1.3 本次实践完成目标 二、 相关服务介绍2.1 华为云ECS云服务器介绍2.2 Node.js介绍 三、环境准备工作3.1 预置实验环境3.2 查看预置环境信息 四、登录华为云4.1 登录华为云4.2 查…

C语言整体梳理-基础篇-结构体

结构体详解 1.1结构体是什么? 结构体是一些值的集合,这些值成为成员变量,结构体的每个成员可以是不同类型的变量。 数组是相同类型的元素组成的集合,结构体可以是不同类型元素组成的集合。 1.2结构体的声明 1.2.1常规声明 s…

【 实战案例篇三】【某金融信息系统项目管理案例分析】

大家好,今天咱们来聊聊金融行业的信息系统项目管理。这个话题听起来可能有点专业,但别担心,我会尽量用大白话给大家讲清楚。金融行业的信息系统项目管理,说白了就是如何高效地管理那些复杂的IT项目,确保它们按时、按预算、按质量完成。咱们今天不仅会聊到一些理论,还会通…

会话与会话管理:Cookie与Session的深度解析

一、什么是会话? 二、Cookie:客户端存储技术 1. Cookie的工作原理 2、在后端设置cookie 3、在前端设置cookie 三、浏览器开启了cookie禁用怎么办? 一、什么是会话? 会话(Session)是指一个用户与服务器之间…

MAVlink链路环境搭建并解决“ModuleNotFoundError: No module named ‘xxx’”问题

MAVlink链路常用于云台相机与飞控以及地面站之间的数据传输,搭建MAVlink链路环境需要安装Python、Future、MAVLink、pymavlink四样工具用于生成mavlink代码。 Python 直接从官网下载默认安装即可https://www.python.org/downloads/ 在电脑命令行进行安装验证&#x…

java后端开发day23--面向对象进阶(四)--抽象类、接口、内部类

(以下内容全部来自上述课程) 1.抽象类 父类定义抽象方法后,子类的方法就必须重写,抽象方法在的类就是抽象类。 1.定义 抽象方法 将共性的行为(方法)抽取到父类之后。由于每一个子类执行的内容是不一样…

Go - 泛型的使用

泛型的语法 泛型为Go语言添加了三个新的重要特性: 函数和类型的类型参数。将接口类型定义为类型集,包括没有方法的类型。类型推断,它允许在调用函数时在许多情况下省略类型参数。 类型参数 类型参数的使用 除了函数中支持类型参数列表外&#xff0c…

蓝桥杯刷题-dp-线性dp(守望者的逃离,摆花,线段)

[NOIP 2007 普及组] 守望者的逃离 题目描述 恶魔猎手尤迪安野心勃勃,他背叛了暗夜精灵,率领深藏在海底的娜迦族企图叛变。 守望者在与尤迪安的交锋中遭遇了围杀,被困在一个荒芜的大岛上。 为了杀死守望者,尤迪安开始对这个荒岛…

内容中台的企业CMS架构是什么?

企业CMS模块化架构 现代企业内容管理系统的核心在于模块化架构设计,通过解耦内容生产、存储、发布等环节构建灵活的技术栈。动态/静态发布引擎整合技术使系统既能处理实时更新的产品文档,也能生成高并发的营销落地页,配合版本控制机制确保内…

算法题(81):询问学号

审题: 需要我们根据给出的n值确定录入数据个数,然后根据给出的数据存储学号。再根据m值确定需要输出的学号个数,然后根据数组内容输出学号 思路: 我们可以利用数组进行数据顺序存储,以及随机读取完成本题 由于学号最大为1e9&#…

React antd的datePicker自定义,封装成组件

一、antd的datePicker自定义 需求:用户需要为日期选择器的每个日期单元格添加一个Tooltip,当鼠标悬停时显示日期、可兑换流量余额和本公会可兑流量。这些数据需要从接口获取。我需要结合之前的代码,确保Tooltip正确显示,并且数据…

C++ AVL树详解(含模拟实现)

目录 AVL树的概念 AVL树节点的定义 AVL树的插入 AVL树的旋转(难点) AVL树的验证 AVL树的删除(本文不做具体的模拟实现) AVL树的性能 AVL树的模拟实现 AVL树的概念 二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索…

Spring Boot 3.x 系列【3】Spring Initializr快速创建Spring Boot项目

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot版本3.0.3 源码地址:https://gitee.com/pearl-organization/study-spring-boot3 文章目录 前言安装JDK 17创建Spring Boot 项目 方式1:网页在线生成方式2&#…

Elasticsearch:过滤 HNSW 搜索,快速模式

作者:来自 Elastic Benjamin Trent 通过我们的 ACORN-1 算法实现,探索我们对 Apache Lucene 中的 HNSW 向量搜索所做的改进。 多年来,Apache Lucene 和 Elasticsearch 一直支持使用 kNN 查询的过滤搜索,允许用户检索符合指定元数据…

【AI测试学习】AnythingLLM+Ollama+DeepSeek部署私人知识库

1.搭建DeepSeek大语言模型 1.1Ollama大预言模型部署 Ollama简化了大型语言模型的运行,让每个人都能在本地轻松体验AI的强大,打开浏览器-下载Ollama-输入命令-搞定,这是本地部署大语言模型的全新方式。 这里我们借助Ollama大预言模型部署工具进行搭建 官网如下:Ollama …