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

【 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,实现用户添加,代码如下:

  1. 实现 mapper 接口
@Mapper
public interface UserInfoMapper {int add(UserInfo userInfo);
}
  1. xml 文件实现
<insert id="add">insert into userinfo(username,password) values (#{username},#{password})
</insert>
  1. service 代码实现
@Service
public class UserService {@Resourceprivate UserInfoMapper userInfoMapper;public int add(UserInfo userInfo){return userInfoMapper.add(userInfo);}
}
  1. 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 可以⽤来修饰⽅法或类:

  1. 修饰⽅法时:需要注意只能应⽤到 public ⽅法上,否则不⽣效
  2. 修饰类时:表明该注解对该类中所有的 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;}

解决方案:

  1. 将异常重新抛出去 throw e; (不推荐)
  2. 手动回滚事务 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

3.2.4 @Transactional ⼯作原理

1.@Transactional 是基于 AOP 实现的,AOP ⼜是使⽤动态代理实现的。若⽬标对象实现了接⼝,默认情况下会采⽤ JDK 的动态代理,若继承了目标对象,会使⽤ CGLIB 动态代理。

2.@Transactional 在开始执⾏业务之前,通过代理先开启事务,在执⾏成功之后再提交事务。如果中途遇到的异常,则回滚事务。

3.@Transactional 实现思路预览:
在这里插入图片描述

4.@Transactional 具体执⾏细节如下图所示:
在这里插入图片描述


四、Spring事务隔离级别

4.1 事务特性回顾:

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

  1. 原⼦性:⼀个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执⾏过程中发⽣错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执⾏过⼀样
  2. ⼀致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写⼊的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以⾃发性地完成预定的⼯作
  3. 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失
  4. 隔离性:数据库允许多个并发事务同时对其数据进⾏读写和修改的能⼒,隔离性可以防⽌多个事务并发执⾏时由于交叉执⾏⽽导致数据的不⼀致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串⾏化(Serializable)

⽽这 4 种特性中,只有隔离性(隔离级别)是可以设置的,那为什么要设置事务的隔离级别?

设置事务的隔离级别是⽤来保障多个并发事务执⾏更可控,更符合操作者预期的,为了防⽌其他的事务影响当前事务执⾏的⼀种策略

4.2 回顾MySQL 事务隔离级别:

  1. READ UNCOMMITTED:读未提交,也叫未提交读,该隔离级别的事务可以看到其他事务中未提交的数据。该隔离级别因为可以读取到其他事务中未提交的数据,⽽未提交的数据可能会发⽣回滚,因此我们把该级别读取到的数据称之为脏数据,把这个问题称之为脏读
  2. READ COMMITTED:读已提交,也叫提交读,该隔离级别的事务能读取到已经提交事务的数据,因此它不会有脏读问题。但由于在事务的执⾏中可以读取到其他事务提交的结果,所以在不同时间的相同 SQL 查询中,可能会得到不同的结果,这种现象叫做不可重复读
  3. REPEATABLE READ:可重复读,是 MySQL 的默认事务隔离级别,它能确保同⼀事务多次查询的结果⼀致。但也会有新的问题,⽐如此级别的事务正在执⾏时,另⼀个事务成功的插⼊了某条数据,但因为它每次查询的结果都是⼀样的,所以会导致查询不到这条数据,⾃⼰重复插⼊时⼜失败(因为唯⼀约束的原因)。明明在事务中查询不到这条信息,但⾃⼰就是插⼊不进去,这就叫幻读(Phantom Read)
  4. 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、代码实现 一、题目描述 原题连接&#xff1a; 203. 移除链表元素 题目描述&#xff1a; 给你一个链表的…...

关于Open Shift(OKD) 中 用户认证、权限管理、SCC 管理的一些笔记

写在前面 因为参加考试&#xff0c;会陆续分享一些 OpenShift 的笔记博文内容为 openshift 用户认证和权限管理以及 scc 管理相关笔记学习环境为 openshift v3 的版本&#xff0c;有些旧这里如果专门学习 openshift &#xff0c;建议学习 v4 版本理解不足小伙伴帮忙指正 对每个…...

活动文章测试(勿删)

大家好&#xff01; 我是CSDN官方博客&#xff01; 恭喜你正式加入CSDN博客&#xff0c;迈上技术成神之路~~ 路漫漫其修远兮——身为技术人&#xff0c;求索之路道阻且艰&#xff0c;但一万次的翘首却比不过一次的前行。 现在&#xff0c;就来开启你的个人博客&#xff0c;发布…...

Windows下 批量重命名文件【bat实现】

目录 前言 一、Windows简单实现重命名 二、使用命令行和Excel实现重命名 前言 在实际应用中&#xff0c;我们经常会遇到将指定文件夹下的文件重命名&#xff0c;以便程序读写。 本文介绍了两种方式&#xff0c;都是在Windows系统中自带的重命名方式。 一、Windows简单实现…...

从 Milvus 2.2 到 2.2.6,我们是如何持续稳定升级的

最近&#xff0c;Milvus 发布了 2.2.6 版本&#xff0c;在修复了一些 bug 后&#xff0c;Milvus 变得越发稳定。 事实上&#xff0c;自 Milvus 升级至 2.X 版本以来&#xff0c;我们一直在努力改进及优化&#xff0c;推出了诸如从文件中批量导入数据、基于磁盘的近似最近邻&…...

自学python有推荐的么

大学生自学那必然是首推B站大学哇能称之为大学不是没有道理的&#xff0c;看看各个领域的学习分享都是非常多的&#xff0c;关键是看着弹幕就感觉像是在和一帮志同道合的小伙伴一起学习&#xff0c;自学的道路也不再孤单了&#xff0c;遇见不会的没准还能在弹幕和评论区找到答案…...

设计模式 --- 行为型模式

一、概述 行为型模式用于描述程序在运行时复杂的流程控制&#xff0c;即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务&#xff0c;它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式&#xff0c;前者采用继承机制来在类间分…...

防御式编程

防御式编程是提高软件质量技术的有益辅助手段。就是一开始不要在代码里引入错误。使用迭代式设计、编码前写伪代码&#xff0c;写测试用例&#xff0c;助于防止引入错误。 断言 断言是用来检查永远不应该发生的非正常情况&#xff0c;处理这些错误的代码 错误处理技术&#xff…...

导出pdf Puppeteer 和 wkhtmltopdf区别

您可以使用第三方的 PDF 生成库来将动态页面导出为 PDF 文件。目前比较常见的是使用 Headless Chrome 或 Puppeteer 这类工具将页面转换为 PDF 文件&#xff0c;具体步骤如下&#xff1a; 安装 Headless Chrome 或 Puppeteer。 使用框架调用后端接口获取数据&#xff0c;渲染出…...

sequelize + Nodejs + MySQL 的简单用法

How to Use Sequelize ORM in NodeJS - Tutorial 1 Sequlize 简介 Sequelize 是最流行的可以与 Nodejs 一起使用的一种关系数据库 ORM (Object-relational mapping 对象关系映射)&#xff0c;Mongoose 是 MongoDB 的 ORM. Sequelize 的作用&#xff0c;简单地说&#xff0c;就…...

Android Jetpack - Navigation 组件:进行应用程序导航

一. Navigation 组件的介绍 1.1 什么是 Navigation 组件 Navigation 组件是一种 Android Jetpack 库&#xff0c;它可以帮助开发者轻松地实现应用程序中的导航功能。导航组件包含多个类和组件&#xff0c;包括导航图、目的地、导航控制器等&#xff0c;可以帮助我们管理应用程…...

MySQL的binlog原理和它的几种使用方法

MySQL中的二进制日志&#xff08;binlog&#xff09;是一种用于记录数据库操作的日志文件&#xff0c;它可以记录MySQL服务器接收到的所有修改数据库的语句&#xff0c;例如INSERT、UPDATE和DELETE等语句。二进制日志对于备份和恢复数据库、复制数据库和进行数据分析等操作非常…...

40岁以上的程序员还容易找到工作吗?聊聊我自己的亲身经历

今天我们来讨论一个比较热门的话题&#xff0c;那就是程序员。如果到了40岁以上还容易找到工作吗&#xff1f;这个问题呢&#xff0c;其实是一个非常现实的问题&#xff0c;也是我们程序员非常关心的一个问题。因为我们每一个程序员&#xff0c;他都会有到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小姿势 - 可选知识点:

可选知识点&#xff1a; 列表推导式 列表和字典推导式 字典推导式 生成器表达式 带条件的生成器表达式 解析XML 解析JSON 使用Requests和BeautifulSoup爬虫 Python并发编程 Python多线程编程 Python多进程编程 Python异步编程 Python装饰器 Python闭包 Python模块化 Python类和…...

Javaee Spring的AOP简介

一.Spring的AOP简介 1.1 什么是AOP AOP 为 Aspect Oriented Programming 的缩写&#xff0c;意思为面向切面编程&#xff0c;是通过预编译方式和运行期动态代 理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续&#xff0c;是软件开发中的一个热点&#xff0c;也是…...

基于ansible初始化linux服务器基础环境。

大家好&#xff0c;今天我要和大家分享一个关于搭建centos环境的新方法。 以前我们经常会看到一些文章介绍如何搭建centos环境&#xff0c;但很多时候都会出现一些问题。不过现在有了一种新的方法&#xff0c;就是使用ansible脚本来实现。 虽然这种方法仅适用于centos7&#…...

leetcode-数据库题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 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提交队列…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...