Spring使用事务的两种方式

1. 为什么需要事务?

前面的博客 对MySQL事务作讲解,事务就是将⼀组操作封装成⼀个执⾏单元(封装到⼀起),要么全部成功,要么全部失败。

比如,现在要实现转账操作:

第一步:张三账户 -500

第二步:李四账户+500

如果没有事务,第一步执行成功,然而第二步执行失败,那么张三的账户的500元就凭空消失了。而事务的引入就可以解决这个问题,让这一组操作要么一起成功,要么一起失败。

2.Spring中事务的实现

Spring中的事务操作分为两类:

  1. 编程式事务(⼿动写代码操作事务)。
  2. 声明式事务(利⽤注解⾃动开启和提交事务)。

之前MySQL博客中,使用事务可以分为3个重要的操作:开启事务、提交事务、回滚事务,它们对应的操作命令如下:

-- 开启业务  (⼀组操作前开启事务)
start transaction;
-- 相关业务执行-- 提交事务  (这组操作全部成功, 提交事务)
commit;-- 回滚事务 (这组操作中间任何⼀个操作出现异常, 回滚事务)
rollback;

2.1 Spring编程式事务(手动)

Spring ⼿动操作事务和上⾯ MySQL 操作事务类似,它也是有 3 个重要操作步骤:
  1. 开启事务(获取)
  2. 提交事务
  3. 回滚事务
SpringBoot 内置了两个对象,DataSourceTransactionManager ⽤来获取事务(开启事务)、提交或回滚事务的,⽽ TransactionDefinition 是事务的属性,在获取事务的时候需要将TransactionDefinition 传递进去从⽽获得⼀个事务 TransactionStatus。 如图所示:

使用编程式事务代码如下:
代码结构:

controller:

@RestController
@RequestMapping("user")
public class UserController {@Autowiredprivate UserService userService;// JDBC 事务管理器@Resourceprivate DataSourceTransactionManager dataSourceTransactionManager;// 定义事务属性@Resourceprivate TransactionDefinition transactionDefinition;@PostMapping("/add")public String addUser(@RequestBody Userinfo user) {// 开启事务TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);userService.addUser(user);//提交事务dataSourceTransactionManager.commit(transactionStatus);//回滚事务//dataSourceTransactionManager.rollback(transactionStatus);return "User added successfully!";}
}

当执行提交事务,观察结果:

数据库:

发现我们程序执行成功并且事务提交完成,持久化到数据库中。

那么如果我们使用的是回滚代码,来添加用户tom,再来观察执行结果:

然而,数据却没有同步到数据库中,因为事务被我们回滚了:

以上代码虽然可以实现事务, 但操作也很繁琐, 有没有更简单的实现⽅法呢? --- 声明式事务

2.2 声明式事务@Transactional

声明式事务的实现很简单, 只需要在需要事务的⽅法上添加 @Transactional 注解就可以实现了⽆需⼿动开启事务和提交事务, 进⼊⽅法时⾃动开启事务, ⽅法执⾏完会⾃动提交事务, 如果中途发⽣ 没有处理的异常会⾃动回滚事务.
代码实现:
注意:
我们⼀般会在业务逻辑层当中来控制事务, 因为在业务逻辑层当中, ⼀个业务功能可能会包含多个数据访问的操作. 在业务逻辑层来控制事务, 我们就可以将多个数据访问操作控制在⼀个事务范围内. 下面代码在Controller中书写, 只是为了⽅便演示学习.
@Transactional
@RestController
@RequestMapping("user")
public class UserController {@Autowiredprivate UserService userService;@PostMapping("/add")public String addUser(@RequestBody Userinfo user) {userService.addUser(user);return "User added successfully!";}
}

现在代码中是没有异常的,也就是实行玩添加业务后就提交了。添加 tom,观察执行结果:

入预期所料,事务被提交,数据持久化到数据库。

现在我们手动来写一个异常,然后添加alice,通过触发异常来实现事务回滚:

 观察结果,数据被回滚:

@Transactional作用

@Transactional 可以⽤来修饰⽅法或类:

  • 修饰⽅法时: 只有修饰public ⽅法时才⽣效(修饰其他⽅法时不会报错, 也不⽣效)[推荐]
  • 修饰类时: 对 @Transactional 修饰的类中所有的 public ⽅法都⽣效.
⽅法/类被 @Transactional 注解修饰时, 在⽬标⽅法执⾏开始之前, 会⾃动开启事务, ⽅法执⾏结束之后, ⾃动提交事务.
注意:
  • 如果在⽅法执⾏过程中, 出现异常, 且异常未被捕获, 就进⾏事务回滚操作.
  • 如果异常被程序捕获, ⽅法就被认为是成功执⾏, 依然会提交事务.
修改上述代码, 对异常进⾏捕获:

 运⾏程序, 发现虽然程序出错了, 但是由于异常被捕获了, 所以事务依然得到了提交.

如果需要事务进⾏回滚, 有以下两种方式:

1. 重新抛出异常:

2. 手动回滚事故

使用 TransactionAspectSupport.currentTransactionStatus() 得到当前的事务, 并使用 setRollbackOnly 设置 setRollbackOnly :

3. @Transactional详解

了解  @Transactional 注解当中的三个常⻅属性:

1. rollbackFor: 异常回滚属性. 指定能够触发事务回滚的异常类型. 可以指定多个异常类型
2. Isolation: 事务的隔离级别. 默认值为 Isolation.DEFAULT
3. propagation: 事务的传播机制. 默认值为 Propagation.REQUIRED

3.1 rollbackFor

@Transactional 默认只在遇到运⾏时异常Error时才会回滚, ⾮运⾏时异常不回滚. 即Exception的⼦类中, 除了RuntimeException及其⼦类.:
上⾯为了演⽰事务回滚, ⼿动设置了程序异常: int a = 10 / 0 ;这属于运行时异常,会发生回滚。
如果我们代码中有一个IOException就不会触发回滚吗?接下来我们把异常改为如下代码检验一下

观察结果:

 发现虽然程序抛出了异常, 但是事务依然进⾏了提交:

如果我们需要所有异常都回滚, 需要来配置 @Transactional 注解当中的 rollbackFor 属性, 通过 rollbackFor 这个属性指定出现何种异常类型时事务进⾏回滚.

 再次执行程序,发现虽然程序抛出了IOException异常,但是事务也回滚了,因为我们修改了rollbackFor 的属性。

结论:

  • 在Spring的事务管理中,默认只在遇到运⾏时异常RuntimeException和Error时才会回滚.
  • 如果需要回滚指定类型的异常, 可以通过rollbackFor属性来指定. 

 写累了.事务的隔离级别和传播机制单独开一节博客来回估吧。

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

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

相关文章

两张图片进行分析

两张图片进行分析&#xff0c;可以拖动左边图片进行放大、缩小查看图片差异 底图 <template><div class"box_container"><section><div class"" v-for"item in imgData.imgDataVal" :key"item.id"><img :s…

Mybatis02-CRUD操作及配置解析

1、CRUD 1.namespace namespace中的包名要和Dao/Mapper 接口的包名一致&#xff01; 1个Dao接口类对应1个mapper&#xff0c;也对应1个namespace&#xff0c; 1个Dao接口中的方法对应1个namespace中一个SQL语句 2.CRUD id&#xff1a;对应的namespace接口中的方法名resul…

html+CSS+js部分基础运用14

熟悉插值{{}}的用法&#xff0c;在页面中显示下列内容。图1 插值语法的效果图 在页面中统计鼠标单机按钮的次数。【提示&#xff1a;v-on指令】&#xff0c;页面效果如下图所示&#xff1a;图2 统计效果图 3、①单击按钮可以修改黑体字。②通过调试工具vue-devtools修改黑体字。…

服务器数据恢复—服务器raid5上层zfs文件系统数据恢复案例

服务器数据恢复环境&故障&#xff1a; 一台某品牌X3650M3服务器&#xff0c;服务器中有一组raid5磁盘阵列&#xff0c;上层采用zfs文件系统。 服务器未知原因崩溃&#xff0c;工作人员排查故障后发现服务器的raid5阵列中有两块硬盘离线导致该阵列不可用&#xff0c;服务器内…

Web3.0区块链技术开发方案丨ICO与IDO代币开发

在Web3.0时代的到来下&#xff0c;区块链技术不仅改变着金融领域的格局&#xff0c;也在资金筹集和代币发行方面掀起了一场变革。初始代币发行&#xff08;ICO&#xff09;和去中心化代币发行&#xff08;IDO&#xff09;成为了项目融资的主要方式&#xff0c;其基于区块链技术…

电脑开机之后要很久才能进入系统?进入WinPE也是卡顿半天?

前言 小白最近接到了一张很奇怪的电脑维修单&#xff0c;客户说他的工作室电脑开机特别慢&#xff0c;开机之后特别卡顿&#xff0c;在使用的时候也会一卡一卡的。 这事情开始看很简单&#xff1a;估计就是电脑还是机械硬盘&#xff0c;所以开机很慢又卡顿。所以应该是把机械…

LSDFi协议赛道4大稳定币项目,以bitget钱包为例

纵览 LSDfi 生态繁荣的基石&#xff0c;LSD 稳定币赛道全解析 近期有许多建立在流动性质押通证的稳定币借贷协议开始出现在大众眼里&#xff0c;今天文章就要带大家来一一了解这些 LSDfi 协议究竟是如何争夺这块诱人的大饼。 LybraFinanceLSD 它透过抵押stETH/ETH 铸造&#…

MySQL经典练习50题(上)(解析版)

所有笔记、生活分享首发于个人博客 想要获得最佳的阅读体验&#xff08;无广告且清爽&#xff09;&#xff0c;请访问本篇笔记 MySQL经典练习50题&#xff08;上&#xff09; 创建数据库和表 -- 建 表 -- 学 生 表 CREATE TABLE Student( s_id VARCHAR(20), s_name VARCHAR(2…

Linux shell编程学习笔记57:lshw命令 获取cpu设备信息

0 前言 在Linux中&#xff0c;获取cpu信息的命令很多&#xff0c;除了我们已经研究的 cat /proc/cpuinfo、lscpu、nproc、hwinfo --cpu 命令&#xff0c;还有 lshw命令。 1 lshw命令的功能 lshw命令源自英文list hardware&#xff0c;即列出系统的硬件信息&#xff0c;这些硬…

C++之noexcept

目录 1.概述 2.noexcept作为说明符 3.noexcept作为运算符 4.传统throw与noexcept比较 5.原理剖析 6.总结 1.概述 在C中&#xff0c;noexcept是一个关键字&#xff0c;用于指定函数不会抛出异常。如果函数保证不会抛出异常&#xff0c;编译器可以进行更多优化&#xff0c;…

C语言.数据结构.单链表经典算法

数据结构.单链表经典算法 1.经典算法OJ题1&#xff1a;移除链表元素1.1题目描述&#xff1a;1.2题解&#xff1a;1.3图文解释&#xff1a; 2.经典算法OJ题2&#xff1a;反转链表2.1题目描述&#xff1a;2.2题解&#xff1a;2.3图文解释 3.经典算法OJ题3&#xff1a;合并两个有序…

编译和运行qemu-uboot-arm64单板的Armbian系统

这篇文章ARM虚拟机安装OMV-CSDN博客遗留一个启动qemu-uboot-arm64单板Armbian镜像的问题&#xff0c;使用官方下载的镜像&#xff0c;会报错&#xff1a; fatal: no kernel available .... Failed to load /vmlinuz ...... qemu-system-aarch64 -smp 8 -m 8G -machine virt …

WPF音乐播放器 零基础4个小时左右

前言&#xff1a;winfrom转wpf用久的熟手说得最多的是,转回去做winfrom难。。当时不明白。。做一个就知道了。 WPF音乐播放器 入口主程序 FontFamily"Microsoft YaHei" FontSize"12" FontWeight"ExtraLight" 居中显示WindowStartupLocation&quo…

数据结构:并查集

数据结构&#xff1a;并查集 题目描述参考代码 题目描述 输入样例 5 5 C 1 2 Q1 1 2 Q2 1 C 2 5 Q2 5输出样例 Yes 2 3参考代码 #include <iostream>using namespace std;const int N 100010;int n, m; int p[N], sz[N];int find(int x) // 返回x的祖宗节点 路径…

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(二十六)- 微服务(6)

目录 10. Docker 10.1 Docker基本操作 10.1.1 镜像相关命令 10.1.2 容器相关命令 10.2 数据卷命令 10.2.1 常用命令 : 10.2.2 挂载数据卷 10. Docker 10.1 Docker基本操作 10.1.1 镜像相关命令 docker --help 查看docker帮助文档 docker images --help 查看docker ima…

Java中条件运算符的嵌套使用技巧总结

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

c语言项目-贪吃蛇项目2-游戏的设计与分析

文章目录 前言游戏的设计与分析地图&#xff1a;这里简述一下c语言的国际化特性相关的知识<locale.h> 本地化头文件类项setlocale函数 上面我们讲到需要打印★&#xff0c;●&#xff0c;□三个宽字符找到这三个字符打印的方式有两种&#xff1a; 控制台屏幕的长宽特性&a…

C++笔试强训day38

目录 1.天使果冻 2.dd爱旋转 3.小红取数 1.天使果冻 链接https://ac.nowcoder.com/acm/problem/219641 一开始都可以想到将数组的前x个数拿出来排降序输出第二个数即可。 但是因为询问量和数据量都较大&#xff0c;每次询问一次都要排序一次数组&#xff0c;会超时&#xf…

ai聊天机器人app的分享!有4个热门的软件!

在科技日新月异的今天&#xff0c;AI聊天机器人已经不再是遥不可及的科幻概念&#xff0c;而是实实在在走进了我们的日常生活。无论是工作中的信息查询&#xff0c;还是生活中的闲聊解闷&#xff0c;这些智能助手都能为我们提供便捷、高效的服务。那么&#xff0c;市面上都有哪…

含有嘧啶的光活性阳离子共轭微孔聚合物通过“吸附杀死”抗菌策略促进感染伤口愈合

引用信息&#xff1a; 文 章&#xff1a;Photoactive cationic conjugated microporous polymers containing pyrimidine with an adsorption-killantibacterial strategy for infected wound healing. 期 刊&#xff1a;Chemical Engineering Journal&#xff08;影响因子…