Spring实现事务二

.

在这里插入图片描述

上一次我们讲到,Spring实现事务的方式有两种,并且,为实现这两种方式,我们做了一些准备工作,那么接下来,我将带着大家,来继续学习事务的相关知识

编程式事务

SpringBoot内置了两个对象
DataSourceTransactionManager 事务管理器. 用来获取事务(开启事务), 提交或回滚事务
TransactionDefinition 是事务的属性, 在获取事务的时候需要将TransactionDefinition 传递进去从而获得⼀个事务TransactionStatus

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class UserInfoController {@Autowiredprivate UserInfoService userInfoService;@Autowired// JDBC 事务管理器private DataSourceTransactionManager dataSourceTransactionManager;@Autowired// 定义事务属性private TransactionDefinition transactionDefinition;@RequestMapping("/login")public String login(String userName,String password){//开启事务TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);Integer result = userInfoService.insert(userName,password);//提交事务dataSourceTransactionManager.commit(transactionStatus);//回滚事务
//        dataSourceTransactionManager.rollback(transactionStatus);if(result<=0){return  "添加失败";}else {return "添加成功";}}
}

运行程序: http://127.0.0.1:8080/login?userName=zhangsan&password=123456
可以看到,当我们的代码中使用事务提交的时候,数据库中确实被插入了userName=zhangsan&password=123456,但是如果采用事务回滚,那么既是打印的日志显示插入成功,数据库中却并没有新增数据

声明式事务@Transactional


@RestController
public class UserInfoController2 {@Autowiredprivate UserInfoService userInfoService;@Transactional( isolation = READ_COMMITTED,rollbackFor = Exception.class)@RequestMapping("/login2")public String login(String userName,String password) throws IOException {Integer result = userInfoService.insert(userName,password);if(result<=0){return  "添加失败";}else {Integer i = 10/0;return "添加成功";}}
}

运行程序,可以看到,当程序出现异常过后,事务就会自动回滚,但是当不存在 Integer i = 10/0;这一句的时候,数据库就会正常新增数据.

@Transactional 作用

可以用来修饰方法或类:
• 修饰方法时: 只有修饰public 方法时才生效(修饰其他方法时不会报错, 也不生效)[推荐]
• 修饰类时: 对 @Transactional 修饰的类中所有的 public 方法都生效.
方法/类被 @Transactional 注解修饰时, 在目标方法执行开始之前, 会自动开启事务, 方法执行结束之后, 自动提交事务.
如果在方法执行过程中, 出现异常, 且异常未被捕获, 就进行事务回滚操作.
如果异常被程序捕获, 方法就被认为是成功执行, 依然会提交事务.

对上述代码进行修改过后,

@RestController
public class UserInfoController2 {@Autowiredprivate UserInfoService userInfoService;@Transactional( isolation = READ_COMMITTED,rollbackFor = Exception.class)@RequestMapping("/login2")public String login(String userName,String password) throws IOException {Integer result = userInfoService.insert(userName,password);if(result<=0){return  "添加失败";}else {try {Integer integer = 10/0;}catch (Exception e){e.printStackTrace();}return "添加成功";}}
}

执行程序,可以看到,程序虽然报错,但是事务依旧提交成功了,数据库的数据已经成功新增了,如果在捕获了异常的情况下,想要将事务进行回滚,有以下两种方式

抛出异常

@RestController
public class UserInfoController2 {@Autowiredprivate UserInfoService userInfoService;@Transactional@RequestMapping("/login2")public String login(String userName,String password){Integer result = userInfoService.insert(userName,password);if(result<=0){return  "添加失败";}else {try {Integer integer = 10/0;}catch (Exception e){throw e;}return "添加成功";}}
}

手动回滚

@RestController
public class UserInfoController2 {@Autowiredprivate UserInfoService userInfoService;@Transactional@RequestMapping("/login2")public String login(String userName,String password){Integer result = userInfoService.insert(userName,password);if(result<=0){return  "添加失败";}else {try {Integer integer = 10/0;}catch (Exception e){TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}return "添加成功";}}
}

@Transactional 详解

rollbackFor

: 异常回滚属性. 指定能够触发事务回滚的异常类型. 可以指定多个异常类型

可以看到,以上两种方式,都可以在捕获异常的情况下进行事务的回滚,但是有特殊情况,@RestController默认只在遇到运行时异常和Error时抛出异常才会回滚, 非运行时异常不回滚. 即Exception的子类中, 除了RuntimeException及其子类.
在这里插入图片描述
这里我们假设抛出一个IOException

@RestController
public class UserInfoController3 {@Autowiredprivate UserInfoService userInfoService;@Transactional@RequestMapping("/login2")public String login(String userName,String password) throws IOException {Integer result = userInfoService.insert(userName,password);if(result<=0){return  "添加失败";}else {if (true){throw new IOException();}return "添加成功";}}
}

结果显示,虽然出现了异常,但事务仍旧提交了
如果我们需要所有异常都回滚, 需要来配置 @Transactional 注解当中的 rollbackFor 属性, 通
过 rollbackFor 这个属性指定出现何种异常类型时事务进行回滚

@RestController
public class UserInfoController3 {@Autowiredprivate UserInfoService userInfoService;@Transactional(rollbackFor = {Exception.class,Error.class})@RequestMapping("/login2")public String login(String userName,String password) throws IOException {Integer result = userInfoService.insert(userName,password);if(result<=0){return  "添加失败";}else {if (true){throw new IOException();}return "添加成功";}}
}

结果显示,事务得到了回滚,数据库中并未添加数据

事务隔离级别

SQL 标准定义了四种隔离级别, MySQL 全都⽀持. 这四种隔离级别分别是:

  1. 读未提交(READ UNCOMMITTED): 读未提交, 也叫未提交读. 该隔离级别的事务可以看到其他事务中未提交的数据.因为其他事务未提交的数据可能会发⽣回滚, 但是该隔离级别却可以读到, 我们把该级别读到的数据称之为脏数据, 这个问题称之为脏读
  2. 读提交(READ COMMITTED): 读已提交, 也叫提交读. 该隔离级别的事务能读取到已经提交事务的数据,该隔离级别不会有脏读的问题.但由于在事务的执⾏中可以读取到其他事务提交的结果, 所以在不同时间的相同 SQL 查询可能会得到不同的结果, 这种现象叫做不可重复读
  3. 可重复读(REPEATABLE READ): 事务不会读到其他事务对已有数据的修改, 即使其他事务已提交. 也就可以确保同⼀事务多次查询的结果⼀致, 但是其他事务新插⼊的数据, 是可以感知到的. 这也就引发了幻读问题. 可重复读, 是 MySQL 的默认事务隔离级别.
    ⽐如此级别的事务正在执⾏时, 另⼀个事务成功的插⼊了某条数据, 但因为它每次查询的结果都是⼀样的, 所以会导致查询不到这条数据, ⾃⼰重复插⼊时⼜失败(因为唯⼀约束的原因). 明明在事务中查询不到这条信息,但⾃⼰就是插⼊不进去, 这个现象叫幻读.
  4. 串⾏化(SERIALIZABLE): 序列化, 事务最⾼隔离级别. 它会强制事务排序, 使之不会发⽣冲突, 从⽽解决了脏读, 不可重复读和幻读问题, 但因为执⾏效率低, 所以真正使⽤的场景并不多
    在数据库中通过以下 SQL 查询全局事务隔离级别和当前连接的事务隔离级别:
select @@global.tx_isolation,@@tx_isolation;

Spring 中事务隔离级别

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

通过以下代码进行实现
在这里插入图片描述

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

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

相关文章

[Angular 基础] - 指令(directives)

[Angular 基础] - 指令(directives) 这里假设已经知道如何创建 Angular 组件以及数据绑定&#xff0c;不然可以参考前两篇笔记&#xff1a; [Angular 基础] - Angular 渲染过程 & 组件的创建 [Angular 基础] - 数据绑定(databinding) 就像中文翻译一样&#xff0c;dire…

【已解决】pt文件转onnx后再转rknn时得到推理图片出现大量锚框变花屏

前言 环境介绍&#xff1a; 1.编译环境 Ubuntu 18.04.5 LTS 2.RKNN版本 py3.8-rknn2-1.4.0 3.单板 迅为itop-3568开发板 一、现象 采用yolov5训练并将pt转换为onnx&#xff0c;再将onnx采用py3.8-rknn2-1.4.0推理转换为rknn&#xff0c;rknn模型能正常转换&#xff0c;…

gem5学习(18):ARM DVFS建模——ARM DVFS modelling

目录 一、Voltage Domains 1、灵活方法&#xff1a;使用命令行标志 2、不太灵活方法&#xff1a;创建 CpuCluster 的子类 二、Clock Domains 三、Adding Clock Domains to an existing simulation 四、The DVFS Handler 1、the number of Voltage Domains does not matc…

养好花草鱼鸟,也能旺家

不少朋友家里既养了鱼鸟&#xff0c;也养了花草&#xff0c;平时逗逗鸟喂喂鱼再赏赏花&#xff0c;真是非常惬意的生活&#xff0c;而用养鱼的水养植物&#xff0c;花草植物会长得格外茂盛。根据这一原理&#xff0c;很多人喜欢在养一些水培花草的时候&#xff0c;顺便养几尾小…

基于SpringBoot+Vue的外卖点餐管理系统

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是墨韵&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML墨韵 学如逆水行舟&#xff0c;不进则退。学习如赶路&#xff0c;不能慢一步。 目录 一、项目简介 二、开发技术与环…

SSM框架,Maven的学习(下)

依赖传递和依赖冲突 依赖传递指的是当一个模块或库 A 依赖于另一个模块或库 B&#xff0c;而 B 又依赖于模块或库 C&#xff0c;那么 A 会间接依赖于 C。这种依赖传递结构可以形成一个依赖树。当我们引入一个库或框架时&#xff0c;构建工具&#xff08;如 Maven、Gradle&…

2024.02.05

复习单向&#xff0c;双向链表&#xff0c;并且实现两种链表的增加和删除功能。 单链表头插 Linklist insert_head(datatype element,Linklist head) { //创建新节点 Linklist screate_node(); if(NULLs) return head; s->dataelement; //1,判断链表为空 if(NULLhea…

第三篇:SQL数据模型、通用语法和语法分类

一&#xff0c;SQL数据模型 &#xff08;一&#xff09;关系型数据库&#xff08;RDBMS&#xff09; 1.概念 &#xff08;百度百科&#xff09;指采用了关系模型来组织数据的数据库&#xff0c;其以行和列的形式存储数据&#xff0c;以便于用户理解&#xff0c;关系型数据库这…

【蓝桥杯选拔赛真题64】python数字塔 第十五届青少年组蓝桥杯python 选拔赛比赛真题解析

python数字塔 第十五届蓝桥杯青少年组python比赛选拔赛真题 一、题目要求 (注:input()输入函数的括号中不允许添加任何信息) 提示信息: 数字塔是由 N 行数堆积而成,最顶层只有一个数,次顶层两个数,以此类推。相邻层之间的数用线连接,下一层的每个数与它上一层左上…

网络安全大赛

网络安全大赛 网络安全大赛的类型有很多&#xff0c;比赛类型也参差不齐&#xff0c;这里以国内的CTF网络安全大赛里面著名的的XCTF和强国杯来介绍&#xff0c;国外的话用DenCon CTF和Pwn2Own来举例 CTF CTF起源于1996年DEFCON全球黑客大会&#xff0c;以代替之前黑客们通过互相…

EasyX图形库学习(三、用easyX控制图形界面中的小球、图片-加载、输出)

目录 小球视频 图像输出函数 loadimage用于从文件中读取图片 putimage在当前设备上绘制指定图像。 initgraph 函数 图片输出 代码详解&#xff1a; 1. 初始化图形界面 2. 设置背景颜色并清除屏幕 3. 加载并显示图片 4. 等待用户输入并退出程序 图形界面中的小球 1…

在云计算环境下保护Java应用程序的有效措施

云计算&#xff08;Cloud&#xff09;技术是近年来计算机科学的一个重要突破。大多数组织已经通过将自己的应用程序移入云平台而获益。不过&#xff0c;如何保证应用程序在第三方服务器上的安全性&#xff0c;是一项艰巨的挑战。 在本文中&#xff0c;我们将重点讨论Java&…

C++ dfs搜索枚举(四十八)【第八篇】

曾经我们讲过枚举算法&#xff0c;那假设我们把枚举算法应用到搜索里呢&#xff1f; 1.搜索枚举 以前我们在进行枚举的时候是用了多层循环嵌套&#xff0c;但是当枚举的变量过多或者是输入的数量的时候就很难利用循环完成枚举了&#xff0c;不过我们可以尝试利用搜索进行枚举。…

自动化诊断测试之CANoe.DIVA入门

目录 0 前言 1 CANoe.DIVA基础 2 CANoe.DIVA TIPs 0 前言 写在前面&#xff1a;如对本文有任何疑问欢迎评论区讨论&#xff0c;希望和大家一起进步。同时HIL测试群欢迎大家加入如有需要也可私信我拉你。VT和DIVA都可以做UDS的自动化测试&#xff0c;但相对VT来说使用DIVA生成…

Redis学习及总结

Redis 快速入门 Redis属于非关系型数据库 SQL应用场景 数据结构固定相关业务对数据安全性一致性要求高 NoSQL应用场景 数据结构不固定对一致性&#xff0c;安全性要求不高性能要求高 &#x1f3af;需要使用Xftp 传输压缩包到虚拟机上 安装好Redis后&#xff0c; 执行命令…

系统架构设计师-21年-上午答案

系统架构设计师-21年-上午答案 更多软考资料 https://ruankao.blog.csdn.net/ 1 ~ 10 1 前趋图(Precedence Graph)是一个有向无环图&#xff0c;记为:→{(Pi,Pj)|Pi must complete before Pj may strat}&#xff0c;假设系统中进程P{P1&#xff0c;P2&#xff0c;P3&#xf…

UE5 PAK包热加载

参考知乎UE5 Pak学习与应用&#xff08;一&#xff09;运行时导入模型 - 知乎 使用的版本为UE5.1 使用插件为HorPatcher和EasyFile Dialog HotPatcher:UE资源热更打包工具HotPatcher | 循迹研究室 ,Github地址为:GitHub - hxhb/HotPatcher: Unreal Engine hot update manage …

最小生成树超详细介绍

目录 一.最小生成树的介绍 1.最小生成树的简介 2.最小生成树的应用 3.最小生成树的得出方法 二.Kruskal算法 1.基本思想&#xff1a; 2.步骤&#xff1a; 3.实现细节&#xff1a; 4.样例分析&#xff1a; 5.Kruskal算法代码实现&#xff1a; 三.Prim算法 1.基本思想…

【多模态大模型】视觉大模型SAM:如何使模型能够处理任意图像的分割任务?

SAM&#xff1a;如何使模型能够处理任意图像的分割任务&#xff1f; 核心思想起始问题: 如何使模型能够处理任意图像的分割任务&#xff1f;5why分析5so分析 总结子问题1: 如何编码输入图像以适应分割任务&#xff1f;子问题2: 如何处理各种形式的分割提示&#xff1f;子问题3:…

【数据结构和算法】--- 基于c语言排序算法的实现(1)

目录 一、排序的概念及其应用1.1排序的概念1.2 排序的应用1.3 常见的排序算法 二、插入排序2.1直接插入排序2.2 希尔排序2.2.1 预排序2.2.2 缩小gap2.2.3 小结 三、选择排序3.1 直接选择排序3.2 堆排序 一、排序的概念及其应用 1.1排序的概念 排序&#xff1a; 所谓排序&…