【 Spring 事务 】
文章目录
- 一、为什么需要事务(简单回顾)
- 二、MySQL 中的事务使⽤
- 三、Spring 中事务的实现
- 3.1 Spring 编程式事务(手动事务)
- 3.2 Spring 声明式事务(自动事务)
- 3.2.1 @Transactional 作⽤范围
- 3.2.2 @Transactional 参数说明
- 3.2.3 @Transactional 不进行事务回滚的情况
- 3.2.4 @Transactional ⼯作原理
- 四、Spring事务隔离级别
一、为什么需要事务(简单回顾)
我们知道事务的简单定义是将⼀组操作封装成⼀个不可分割的执⾏单元(封装到⼀起),要么全部成功,要么全部失败(通过回滚)
举个例子:⽐如转账分为两个操作,第⼀步操作:A 账户 -100 元,第⼆步操作:B 账户 +100 元
如果没有事务,第⼀步执⾏成功了,第⼆步执⾏失败了,那么 A 账户的 100 元就平⽩⽆故消失了。⽽如果使⽤事务就可以解决这个问题,让这⼀组操作要么⼀起成功,要么⼀起失败
二、MySQL 中的事务使⽤
事务在 MySQL 有 3 个重要的操作:开启事务、提交事务、回滚事务,它们对应的操作命令如下:
--开启事务
start transaction;-- 业务执⾏-- 提交事务
commit;
-- 或回滚事务
rollback;
三、Spring 中事务的实现
3.1 Spring 编程式事务(手动事务)
Spring ⼿动操作事务(编程式事务)和上⾯ MySQL 操作事务类似,它也是有 3 个重要操作步骤:
开启事务(获取事务),提交事务或回滚事务。
具体如何在 spring 中实现呢?SpringBoot 内置了两个对象,DataSourceTransactionManager ⽤来获取事务(开启事务)、提交或回滚事务的,⽽ TransactionDefinition 是事务的属性,在获取事务的时候需要将TransactionDefinition 传递进去从⽽获得⼀个事务 TransactionStatus,实现用户添加,代码如下:
- 实现 mapper 接口
@Mapper
public interface UserInfoMapper {int add(UserInfo userInfo);
}
- xml 文件实现
<insert id="add">insert into userinfo(username,password) values (#{username},#{password})
</insert>
- service 代码实现
@Service
public class UserService {@Resourceprivate UserInfoMapper userInfoMapper;public int add(UserInfo userInfo){return userInfoMapper.add(userInfo);}
}
- controller 中的代码实现(编程式业务实现)
@RestController
public class UserController {@Resourceprivate UserService userService;@Resourceprivate LogService logService;//通过注入的方式,而不是 new 对象@Resource//事务管理器,负责管理事务的行为,比如开始,提交,回滚等操作private DataSourceTransactionManager transactionManager;@Resource//是对事务属性的相关定义,比如设置事务的隔离传播机制,超时时间等private TransactionDefinition transactionDefinition;// 在此方法中使用编程式的事务@RequestMapping("/add")public int add(UserInfo userInfo) {// 非空效验【验证用户名和密码不为空】if (userInfo == null || !StringUtils.hasLength(userInfo.getUsername())|| !StringUtils.hasLength(userInfo.getPassword())) {return 0;}// 开启事务(获取事务)TransactionStatus transactionStatus =transactionManager.getTransaction(transactionDefinition);//执行业务代码 int result = userService.add(userInfo);System.out.println("受影响的行数:" + result);//transactionManager.commit(transactionStatus); // 提交事务//transactionManager.rollback(transactionStatus); // 回滚事务return result;}
}
4.1 获取到事务后,我们先验证提交事务后的效果 ! 通过 url 访问,再观察数据库的结果,如下
执行之前的数据表

通过 url 访问,得到受影响的行数为1

再次查看数据表

由此可见,数据添加成功 !!
4.2 再来验证事务回滚的效果 !!将事务提交的代码注释掉,添加事务回滚代码。紧接上面的数据表来验证
通过 url 访问,得到受影响的行数为1

查看数据表

我们发现,开起事务回滚后,数据表中并没有我们添加的那组数组,由此可见事务回滚成功了
扩展知识点:
如果我仅仅只是开启了事务,而不进行提交事务或回滚事务,这时我的操作也会达到回滚的效果。因为当你没有使用 commit 提交事务时,系统会认为没有提交事务,业务操作会自动回滚,因此数据不会持久化,这是一种保护机制,避免误提交!!
3.2 Spring 声明式事务(自动事务)
声明式事务的实现很简单,只需要在需要的⽅法上添加 @Transactional 注解就可以实现了,⽆需⼿动开启事务和提交事务,进⼊⽅法时⾃动开启事务,⽅法执⾏完会⾃动提交事务,如果中途发⽣了没有处理的异常会⾃动回滚事务,具体实现代码如下:
//注意:修饰方法时,该注解只能加到 Public修饰的方法上。修饰类时:表明该注解对该类中所有的 public ⽅法都⽣效@Transactional@RequestMapping("/add1")public int add1(UserInfo userInfo) {// 非空效验【验证用户名和密码不为空】if (userInfo == null || !StringUtils.hasLength(userInfo.getUsername())|| !StringUtils.hasLength(userInfo.getPassword())) {return 0;}int result = userService.add(userInfo);System.out.println("受影响的行数:" + result);//int num = 10/0;return result;}
对比编程式事务,我们并没有繁琐的步骤,只添加了一个 @Transaction 注解,下面我们看效果

添加事务之前的数据表

添加事务之后的数据表

显而易见,我们添加数据成功了 !!
当我们的方法中出现了一个异常,我们再次验证事务是否会自动回滚呢? 将上面代码中的
int num = 10/0 异常解开注释

再次查看数据表

我们发现表中并没有我们添加的数据 !! 由此可见事务发生了回滚,添加操作失败了
3.2.1 @Transactional 作⽤范围
@Transactional 可以⽤来修饰⽅法或类:
- 修饰⽅法时:需要注意只能应⽤到 public ⽅法上,否则不⽣效
- 修饰类时:表明该注解对该类中所有的 public ⽅法都⽣效
3.2.2 @Transactional 参数说明

3.2.3 @Transactional 不进行事务回滚的情况
前面我们知道,当方法中存在异常时,我们的 @Transaction 会自动进行事务回滚 !但是当我们把这个异常捕获后即进行try…catch 处理,回滚事务就会失效,如下:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();@Transactional@RequestMapping("/add2")public int add2(UserInfo userInfo) {// 非空效验【验证用户名和密码不为空】if (userInfo == null || !StringUtils.hasLength(userInfo.getUsername())|| !StringUtils.hasLength(userInfo.getPassword())) {return 0;}int result = userService.add(userInfo);System.out.println("受影响的行数:" + result);try {int num = 10 / 0;} catch (Exception e) {// throw e;// TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}return result;}
解决方案:
- 将异常重新抛出去 throw e; (不推荐)
- 手动回滚事务 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
3.2.4 @Transactional ⼯作原理
1.@Transactional 是基于 AOP 实现的,AOP ⼜是使⽤动态代理实现的。若⽬标对象实现了接⼝,默认情况下会采⽤ JDK 的动态代理,若继承了目标对象,会使⽤ CGLIB 动态代理。
2.@Transactional 在开始执⾏业务之前,通过代理先开启事务,在执⾏成功之后再提交事务。如果中途遇到的异常,则回滚事务。
3.@Transactional 实现思路预览:

4.@Transactional 具体执⾏细节如下图所示:

四、Spring事务隔离级别
4.1 事务特性回顾:
事务有4 ⼤特性(ACID),原⼦性、持久性、⼀致性和隔离性,具体概念如下:
- 原⼦性:⼀个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执⾏过程中发⽣错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执⾏过⼀样
- ⼀致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写⼊的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以⾃发性地完成预定的⼯作
- 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失
- 隔离性:数据库允许多个并发事务同时对其数据进⾏读写和修改的能⼒,隔离性可以防⽌多个事务并发执⾏时由于交叉执⾏⽽导致数据的不⼀致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串⾏化(Serializable)
⽽这 4 种特性中,只有隔离性(隔离级别)是可以设置的,那为什么要设置事务的隔离级别?
设置事务的隔离级别是⽤来保障多个并发事务执⾏更可控,更符合操作者预期的,为了防⽌其他的事务影响当前事务执⾏的⼀种策略
4.2 回顾MySQL 事务隔离级别:
- READ UNCOMMITTED:读未提交,也叫未提交读,该隔离级别的事务可以看到其他事务中未提交的数据。该隔离级别因为可以读取到其他事务中未提交的数据,⽽未提交的数据可能会发⽣回滚,因此我们把该级别读取到的数据称之为脏数据,把这个问题称之为脏读
- READ COMMITTED:读已提交,也叫提交读,该隔离级别的事务能读取到已经提交事务的数据,因此它不会有脏读问题。但由于在事务的执⾏中可以读取到其他事务提交的结果,所以在不同时间的相同 SQL 查询中,可能会得到不同的结果,这种现象叫做不可重复读
- REPEATABLE READ:可重复读,是 MySQL 的默认事务隔离级别,它能确保同⼀事务多次查询的结果⼀致。但也会有新的问题,⽐如此级别的事务正在执⾏时,另⼀个事务成功的插⼊了某条数据,但因为它每次查询的结果都是⼀样的,所以会导致查询不到这条数据,⾃⼰重复插⼊时⼜失败(因为唯⼀约束的原因)。明明在事务中查询不到这条信息,但⾃⼰就是插⼊不进去,这就叫幻读(Phantom Read)
- SERIALIZABLE:序列化,事务最⾼隔离级别,它会强制事务排序,使之不会发⽣冲突,从⽽解决了脏读、不可重复读和幻读问题,但因为执⾏效率低,所以真正使⽤的场景并不多

● 脏读:⼀个事务读取到了另⼀个事务修改的数据之后,后⼀个事务⼜进⾏了回滚操作,从⽽导致第⼀个事务读取的数据是错误的。
● 不可重复读:⼀个事务两次查询得到的结果不同,因为在两次查询中间,有另⼀个事务把数据修改了(侧重点为 修改)。
● 幻读:⼀个事务两次查询中得到的结果集不同,因为在两次查询中另⼀个事务有新增了⼀部分数据(侧重点为 添加和删除)
在数据库中如何查询全局事务隔离级别和当前连接的事务隔离级别 !!
select @@global.tx_isolation,@@tx_isolation;
以上 SQL 的执⾏结果如下:

4.3 Spring 事务隔离级别:
相⽐于 MySQL 的事务隔离级别,Spring 的事务隔离级别只是多了⼀个 Isolation.DEFAULT(以所连接数据库的全局事务隔离级别为主)

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

相关文章:
【 Spring 事务 】
文章目录 一、为什么需要事务(简单回顾)二、MySQL 中的事务使⽤三、Spring 中事务的实现3.1 Spring 编程式事务(手动事务)3.2 Spring 声明式事务(自动事务)3.2.1 Transactional 作⽤范围3.2.2 Transactional 参数说明3.2.3 Transactional 不进行事务回滚的情况3.2.4 Transactio…...
【刷题之路】LeetCode 203. 移除链表元素
【刷题之路】LeetCode 203. 移除链表元素 一、题目描述二、解题1、方法1——在原链表上动刀子1.1、思路分析1.2、代码实现 2、方法2——使用额外的链表2.1、思路分析2.2、代码实现 一、题目描述 原题连接: 203. 移除链表元素 题目描述: 给你一个链表的…...
关于Open Shift(OKD) 中 用户认证、权限管理、SCC 管理的一些笔记
写在前面 因为参加考试,会陆续分享一些 OpenShift 的笔记博文内容为 openshift 用户认证和权限管理以及 scc 管理相关笔记学习环境为 openshift v3 的版本,有些旧这里如果专门学习 openshift ,建议学习 v4 版本理解不足小伙伴帮忙指正 对每个…...
活动文章测试(勿删)
大家好! 我是CSDN官方博客! 恭喜你正式加入CSDN博客,迈上技术成神之路~~ 路漫漫其修远兮——身为技术人,求索之路道阻且艰,但一万次的翘首却比不过一次的前行。 现在,就来开启你的个人博客,发布…...
Windows下 批量重命名文件【bat实现】
目录 前言 一、Windows简单实现重命名 二、使用命令行和Excel实现重命名 前言 在实际应用中,我们经常会遇到将指定文件夹下的文件重命名,以便程序读写。 本文介绍了两种方式,都是在Windows系统中自带的重命名方式。 一、Windows简单实现…...
从 Milvus 2.2 到 2.2.6,我们是如何持续稳定升级的
最近,Milvus 发布了 2.2.6 版本,在修复了一些 bug 后,Milvus 变得越发稳定。 事实上,自 Milvus 升级至 2.X 版本以来,我们一直在努力改进及优化,推出了诸如从文件中批量导入数据、基于磁盘的近似最近邻&…...
自学python有推荐的么
大学生自学那必然是首推B站大学哇能称之为大学不是没有道理的,看看各个领域的学习分享都是非常多的,关键是看着弹幕就感觉像是在和一帮志同道合的小伙伴一起学习,自学的道路也不再孤单了,遇见不会的没准还能在弹幕和评论区找到答案…...
设计模式 --- 行为型模式
一、概述 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分…...
防御式编程
防御式编程是提高软件质量技术的有益辅助手段。就是一开始不要在代码里引入错误。使用迭代式设计、编码前写伪代码,写测试用例,助于防止引入错误。 断言 断言是用来检查永远不应该发生的非正常情况,处理这些错误的代码 错误处理技术ÿ…...
导出pdf Puppeteer 和 wkhtmltopdf区别
您可以使用第三方的 PDF 生成库来将动态页面导出为 PDF 文件。目前比较常见的是使用 Headless Chrome 或 Puppeteer 这类工具将页面转换为 PDF 文件,具体步骤如下: 安装 Headless Chrome 或 Puppeteer。 使用框架调用后端接口获取数据,渲染出…...
sequelize + Nodejs + MySQL 的简单用法
How to Use Sequelize ORM in NodeJS - Tutorial 1 Sequlize 简介 Sequelize 是最流行的可以与 Nodejs 一起使用的一种关系数据库 ORM (Object-relational mapping 对象关系映射),Mongoose 是 MongoDB 的 ORM. Sequelize 的作用,简单地说,就…...
Android Jetpack - Navigation 组件:进行应用程序导航
一. Navigation 组件的介绍 1.1 什么是 Navigation 组件 Navigation 组件是一种 Android Jetpack 库,它可以帮助开发者轻松地实现应用程序中的导航功能。导航组件包含多个类和组件,包括导航图、目的地、导航控制器等,可以帮助我们管理应用程…...
MySQL的binlog原理和它的几种使用方法
MySQL中的二进制日志(binlog)是一种用于记录数据库操作的日志文件,它可以记录MySQL服务器接收到的所有修改数据库的语句,例如INSERT、UPDATE和DELETE等语句。二进制日志对于备份和恢复数据库、复制数据库和进行数据分析等操作非常…...
40岁以上的程序员还容易找到工作吗?聊聊我自己的亲身经历
今天我们来讨论一个比较热门的话题,那就是程序员。如果到了40岁以上还容易找到工作吗?这个问题呢,其实是一个非常现实的问题,也是我们程序员非常关心的一个问题。因为我们每一个程序员,他都会有到40岁的那一天。 首先…...
Class类
package com.hspedu.reflection.class_;import com.hspedu.Cat;import java.util.ArrayList;/*** author 韩顺平* version 1.0* 对Class类特点的梳理*/ public class Class01 {public static void main(String[] args) throws ClassNotFoundException {//看看Class类图//1. Cla…...
Python小姿势 - 可选知识点:
可选知识点: 列表推导式 列表和字典推导式 字典推导式 生成器表达式 带条件的生成器表达式 解析XML 解析JSON 使用Requests和BeautifulSoup爬虫 Python并发编程 Python多线程编程 Python多进程编程 Python异步编程 Python装饰器 Python闭包 Python模块化 Python类和…...
Javaee Spring的AOP简介
一.Spring的AOP简介 1.1 什么是AOP AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代 理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续,是软件开发中的一个热点,也是…...
基于ansible初始化linux服务器基础环境。
大家好,今天我要和大家分享一个关于搭建centos环境的新方法。 以前我们经常会看到一些文章介绍如何搭建centos环境,但很多时候都会出现一些问题。不过现在有了一种新的方法,就是使用ansible脚本来实现。 虽然这种方法仅适用于centos7&#…...
leetcode-数据库题
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 175. 组合两个表176. 第二高的薪水177. 第N高的薪水178. 分数排名181. 超过经理收入的员工182. 查找重复的电子邮箱183. 从不订购的客户 175. 组合两个表 select p…...
[元来学NVMe协议] NVMe IO 指令集(NVM 指令集)| Flush 命令
声明 主页:元存储的博客_CSDN博客 依公开知识及经验整理,如有误请留言。 个人辛苦整理,付费内容,禁止转载。 内容摘要 前言 NVMe2.0 定义的三类命令集: 管理命令集、IO命令集、Fabrics命令集 Admin Command Set (管理命令集):用于控制器的管理,如创建/销毁IO提交队列…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...
Linux 下 DMA 内存映射浅析
序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...
Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合
无论是python,或者java 的大型项目中,都会涉及到 自身平台微服务之间的相互调用,以及和第三发平台的 接口对接,那在python 中是怎么实现的呢? 在 Python Web 开发中,FastAPI 和 Django 是两个重要但定位不…...
轻量级Docker管理工具Docker Switchboard
简介 什么是 Docker Switchboard ? Docker Switchboard 是一个轻量级的 Web 应用程序,用于管理 Docker 容器。它提供了一个干净、用户友好的界面来启动、停止和监控主机上运行的容器,使其成为本地开发、家庭实验室或小型服务器设置的理想选择…...
【java面试】微服务篇
【java面试】微服务篇 一、总体框架二、Springcloud(一)Springcloud五大组件(二)服务注册和发现1、Eureka2、Nacos (三)负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...
Docker、Wsl 打包迁移环境
电脑需要开启wsl2 可以使用wsl -v 查看当前的版本 wsl -v WSL 版本: 2.2.4.0 内核版本: 5.15.153.1-2 WSLg 版本: 1.0.61 MSRDC 版本: 1.2.5326 Direct3D 版本: 1.611.1-81528511 DXCore 版本: 10.0.2609…...
