当前位置: 首页 > 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提交队列…...

信息的相关性和冗余度:信息在整个文明中的作用

文章目录 I 古埃及的象形文字1.1 罗塞塔石碑1.2 古埃及文字音节和希腊字母的对应表1.3 破解古埃及文字 I 古埃及的象形文字 1.1 罗塞塔石碑 这个石碑是在公元前196年埃及国王托勒密五世加冕一周年的诏书。 在此前大约一百年&#xff0c;埃及已经被来自希腊北方城邦的亚历山大…...

python数据结构与算法-动态规划(最长公共子序列)

一、最长公共子序列问题 1、问题概念 一个序列的子序列是在该序列中删去若干元素后得 到的序列。 例如&#xff1a;"ABCD”和“BDF”都是“ABCDEFG”的子序列。 最长公共子序列(LCS) 问题: 给定两个序列X和Y&#xff0c;求X和Y长度最大的公共子字列。 例:X"ABBCBDE”…...

Java版企业电子招投标系统源码 Spring Cloud+Spring Boot 电子招标采购系统功能清单

一、立项管理 1、招标立项申请 功能点&#xff1a;招标类项目立项申请入口&#xff0c;用户可以保存为草稿&#xff0c;提交。 2、非招标立项申请 功能点&#xff1a;非招标立项申请入口、用户可以保存为草稿、提交。 3、采购立项列表 功能点&#xff1a;对草稿进行编辑&#x…...

【c语言】函数的基本概念 | 函数堆栈调用原理

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…...

Vue.prototype 详解及使用

前言&#xff1a; 我们可能会在很多组件里用到数据/实用工具&#xff0c;但是不想污染全局作用域。这种情况下&#xff0c;可以通过在原型上定义它们使其在每个 Vue 的实例中可用。 1. 基本示例 在main.js中添加一个变量到 Vue.prototype Vue.prototype.$appName My App这…...

音视频八股文(3)--ffmpeg常见命令(2)

07-ffplay命令播放媒体 播放本地文件 播放本地 MP4 视频文件 test.mp4 的命令&#xff0c;从第 2 秒位置开始播放&#xff0c;播放时长为 10 秒&#xff0c;并且在窗口标题中显示 “test time”&#xff1a; ffplay -window_title "test time" -ss 2 -t 10 -autoe…...

使用bert4keras出现的问题(Process finished with exit code -1073741819 (0xC0000005))

1、环境 python 3.7.12 tensorflow 1.15 keras 2.3.1 bert4keras 0.9.7 protobuf 3.19.0 numpy 1.16.5 2、出现问题 numpy版本不兼容问题所以你就直接按照我的版本就可以了&#xff08;numpy 1.16.5&#xff09; Process finished with exit code -1073741819 (0xC0000005) …...

python协程实战

协程简介 协程(Coroutine)又称微线程、纤程&#xff0c;协程不是进程或线程&#xff0c;其执行过程类似于 Python 函数调用&#xff0c;Python 的 asyncio 模块实现的异步IO编程框架中&#xff0c;协程是对使用 async 关键字定义的异步函数的调用; 一个进程包含多个线程,类似…...

【论文笔记】VideoGPT: Video Generation using VQ-VAE and Transformers

论文标题&#xff1a;VideoGPT: Video Generation using VQ-VAE and Transformers 论文代码&#xff1a;https://wilson1yan. github.io/videogpt/index.html. 论文链接&#xff1a;https://arxiv.org/abs/2104.10157 发表时间&#xff1a; 2021年9月 Abstract 作者提出了…...

scala之基础面向对象

scala 既是面向对象 也是函数式编程 从Java 发展而来&#xff0c;依赖JVM环境 一、 scala 在linux中运行 scala 模式中直接编写运行 scala文件&#xff0c;load执行 scala编译程序 编译 运行 scala java 二、scala 数据类型 基础数据类型 val 不可变变量 函数式编程 …...