Spring中的事务和事务的传播机制

事务是一组操作的集合,不可以被分割。事务会把所有的操作作为一个整体,这组操作要么全部成功,要么全部失败。

事务有三种操作:

  1. 开启事务;
  2. 提交事务;
  3. 回滚事务。

如果代码的执行逻辑是这样:

开启事务业务A回滚事务

此时A当中的所有操作都不会生效

开启事务业务A提交事务

开启事务后只有这种情况下A中的逻辑才生效

Spring中事务的实现有两种

编程式(手动操作事务)

Spring Boot对于事务操作内置了两个类,我们在使用时可以选择直接注入:

  • DataSourceTransactionManager:事务管理器,里面包含了事务的操作和获取;
  • TransactionDefinition:事务的属性。在获取事务时需要充当参数。

提交事务

@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {//获取事务管理器@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;//获取事务属性@Autowiredprivate TransactionDefinition definition;@Autowiredprivate UserMapper userMapper;@RequestMapping("/fun1")public void fun1() {//获取并开启事务TransactionStatus transaction = dataSourceTransactionManager.getTransaction(definition);//业务操作//向数据库中插入一条数据userMapper.userInsert("zhangsan","man");//打印日志log.info("数据插入完成");//提交事务dataSourceTransactionManager.commit(transaction);}
}
@Mapper
public interface UserMapper {@Insert("insert into userinfo(username,gender) values (#{userName},#{gender});")void userInsert(String userName, String gender);
}

这是数据库的初始状态

代码执行后数据成功插入

回滚事务

@RequestMapping("/fun1")
public void fun1() {//获取并开启事务TransactionStatus transaction = dataSourceTransactionManager.getTransaction(definition);//业务操作userMapper.userInsert("zhangsan","man");log.info("数据插入完成");//提交事务
//        dataSourceTransactionManager.commit(transaction);//回滚事务dataSourceTransactionManager.rollback(transaction);
}

当代码执行成功后,数据库中的数据并没有变多。

注解式(利用注解自动实现事务)

使用注解实现事务是非常简单的只需要给需要添加事务的方法加上@Transactional注解。添加该注解后程序会自动的在方法开始前开启事务,在方法结束后提交事务;如果在方法执行中发生了没有处理的异常会自动进行回滚事务

@Transactional既可以修饰方法也可以修饰类:

  1. 修饰方法时该方法必须是被public修饰的方法,否则既不会生效也不会报错;
  2. 当修饰类时,会对该类中的所有被public修饰的方法生效。

当方法正常执行完毕后会自动提交事务 :

@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;@Transactional@RequestMapping("/fun2")public void fun2() {userMapper.userInsert("lisi","man");log.info("数据插入完成");}
}

当方法执行过程中发生异常时自动回滚事务 (该注解默认只回滚运行时异常<RuntimeException
>和错误<error>):

发生运行时异常,事务回滚:

@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;@Transactional@RequestMapping("/fun2")public void fun2() {userMapper.userInsert("lisi111","man");log.info("数据插入完成");//发生运行时异常,事务回滚throw new RuntimeException();}
}

编译时异常不会回滚:

@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;@Transactional@RequestMapping("/fun2")public void fun2() throws IOException {userMapper.userInsert("lisi111","man");log.info("数据插入完成");//发生编译时异常,事务不会回滚throw new IOException();}
}

此时尽管程序已经报错了,可数据还是正常插入了。如何解决这个问题呢?

rollbackFor

可以通过配置 @Transactional 注解当中的 rollbackFor 属性,通过 rollbackFor 这个属性来指定出现何种异常类型时事务进行回滚。

这个属性的类型是数组需要注意

Class<? extends Throwable>[] rollbackFor() default {};
@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;//此时会回滚所有的Exception类型的异常@Transactional(rollbackFor = {Exception.class})@RequestMapping("/fun2")public void fun2() throws IOException {userMapper.userInsert("lisi222","man");log.info("数据插入完成");//此时发生编译时异常,事务回滚throw new IOException();}
}

此时error类型的错误依然会进行回滚。

@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;@Transactional(rollbackFor = {Exception.class})@RequestMapping("/fun2")public void fun2() {userMapper.userInsert("lisi222","man");log.info("数据插入完成");//会发生栈溢出错误,仍然会回滚while(true) {fun2();}}
}

手动回滚事务

使用 TransactionAspectSupport.currentTransactionStatus() 得到当前的事务,并使用setRollbackOnly使事务进行回滚

@Slf4j
@RestController
@RequestMapping("/trans")
public class Test {@Autowiredprivate UserMapper userMapper;@Transactional(rollbackFor = {Exception.class})@RequestMapping("/fun2")public void fun2() {userMapper.userInsert("66666","man");log.info("数据插入完成");//手动设置回滚事务TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}
}

事务隔离级别

SQL中的事务隔离级别:

  1. 读未提交(READ UNCOMMITTED):读未提交,也叫未提交读。该隔离级别的事务可以看到其他事务中未提交的数据(未提交的数据可能会发生回滚,但是该隔离级别却可以读到,这个问题称之为脏读)
  2. 读已提交(READ COMMITTED):也叫提交读,该隔离级别的事务能读取到已经提交事务的数据。(该隔离级别不会有脏读的问题。但由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同SQL查询可能会得到不同的结果,这种现象叫做不可重复读)
  3. 可重复读(REPEATABLE READ):事务不会读到其他事务对已有数据的修改,即使其他事务已提交。可重复读,是MySQL的默认事务隔离级别。(虽然可以确保同一事务多次查询的结果一致,但是其他事务新插入的数据,是可以感知到A事务正在执行时,另⼀个事务成功的插入了某条数据,而此时A事务如果再查寻数据库就会导致两次查找到的“结果集”不同<数据变多了>,这个现象叫幻读。)
  4. 串行化(SERIALIZABLE):序列化,事务最高隔离级别。它会强制事务排序,使之不会发生冲突,从而解决了脏读,不可重复读和幻读问题,但因为执行效率低,所以真正使用的场景并不多。

Spring中的事务隔离级别:

  1. Isolation.DEFAULT :以连接的数据库的事务隔离级别为主;
  2. Isolation.READ_UNCOMMITTED :读未提交;
  3. Isolation.READ_COMMITTED :读已提交;
  4. Isolation.REPEATABLE_READ :可重复读;
  5. Isolation.SERIALIZABLE :串行化;

事务隔离级别可以通过 @Transactional 中的 isolation 属性进行设置

@Transactional(isolation = Isolation.DEFAULT)
@RequestMapping("/fun2")
public void fun2() {}

事务的传播机制

如果A方法中调用B方法那么B方法是使用A方法的事务还是自己的事务,事务的传播机制就是为了解决该问题。

@Transactional 注解支持事务传播机制的设置,通过 propagation 属性来设置。

Spring 事务传播机制有 7 种(在A方法中调用B(七种传播机制都设置在该方法上)方法):

  1. Propagation.REQUIRED:默认的事务传播级别。如果A存在事务,则B加入该事务。如果A没有事务,则B创建一个新的事务;
  2. Propagation.SUPPORTS:如果A存在事务,则B加入该事务。如果A没有事务,则B以非事务的方式继续运行;
  3. Propagation.MANDATORY:强制性。如果A存在事务,则B加入该事务。如果A没有事务,B抛出异常;
  4. Propagation.REQUIRES_NEW:创建一个新的事务。不管A是否开启事务,B都会重新创建一个事务,且创建的事务相互独立,互不干扰;
  5. Propagation.NOT_SUPPORTED:以非事务方式运行。无论A是否存在事务,B都以非事务运行;
  6. Propagation.NEVER:以非事务方式运行。如果A存在事务,则抛出异常;
  7. Propagation.NESTED :如果A存在事务,则B创建一个事务作为当前事务的嵌套事务来运行。如果A没有事务,B创建一个事务。
@Transactional(propagation = Propagation.MANDATORY)
@RequestMapping("/fun2")
public void fun2() {}

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

dolphinscheduler海豚调度(三)SQL任务

在之前的博文中&#xff0c;我们已经介绍了DolphinScheduler海豚调度的基本概念和模块&#xff0c;安装部署和元数据切换&#xff0c;以及Shell任务的实践。今天&#xff0c;让我们来深入探讨DolphinScheduler中另一种常见的任务类型&#xff1a;SQL任务。 SQL任务是DolphinSc…

弹窗内容由后端返回,如何让点击按钮的事件交由前端控制?

一、场景 背景&#xff1a;因为系统里经常有新活动或者公告需要通知所有用户&#xff0c;希望前端维护的这个弹窗里的内容可以由后端接口返回。这样就不需要每次上新活动的时候&#xff0c;前端项目都发版了。因此&#xff0c;前端维护了这个弹窗和它的关闭事件&#xff0c;至…

人工智能之Tensorflow常用API

TensorFlow的计算表现为数据流图&#xff0c;所以tf.Graph类中包含一系列表示计算的操作对象(tf.Operation)&#xff0c;以及在操作之间流动的数据–张量对象(tf.Tensor)。 Graph tf.Graph类包含图相关的API操作&#xff0c;可以在jupyter notebook导入tensorflow之后执行hel…

前端Vue项目无法启动服务,提示无 ‘dev‘ npm的脚本问题解决

目录 一、问题详情 二、问题解决 一、问题详情 上周还能运行的项目&#xff0c;今天突然无法执行了&#xff0c;连最基本的启动按钮也没有了&#xff0c;所有的项目本地都突然跑不起来了&#xff0c;附上截图。 二、问题解决 后来排查的根本原因有点奇葩&#xff0c;是因为…

【踏雪无痕的痕四】——0到底是有还是没有?

目录 一、背景介绍三、过程1.0的历史发展&#xff1f;2.如何将0讲给一个刚上一年级的孩子&#xff1f;3.0的边界和意义&#xff1f;4.那四年&#xff0c;到底在培养什么&#xff1f;和0有什么关系&#xff1f; 四、总结 一、背景介绍 最近在看一年级数学&#xff0c;其中介绍到…

javaWeb个人学习02

会话技术 会话: 用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束.在一次会话中包含多次请求和响应 会话跟踪: 一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一个浏览器,以便在同一次会话的多次请求之间共享数据 会话跟踪方案: …

艺术作品展示图片介绍PR相册视频模板

高级感艺术风格摄影、绘画作品展示文字介绍PR图片相册照片视频模板mogrt下载。 Premiere Pro 2023及以上版本&#xff0c;不需要插件&#xff0c;高清&#xff08;19201080&#xff09;分辨率/30fps&#xff0c;易于定制&#xff0c;持续时间01:00秒&#xff0c;包含PDF帮助文件…

猜猜心里数字(个人学习笔记黑马学习)

1.定义一个变量&#xff0c;数字类型&#xff0c;内容随意 2.基于input语句输入猜想的数字&#xff0c;通过if和多次elif的组合&#xff0c;判断猜想数字是否和心里数字一致 num5if int(input("请输入第一次猜想的数字&#xff1a;"))5:print("猜对了&#xff0…

三分钟一起了解工作流拖拽

低代码技术平台是如今深受很多行业喜爱的得力助手&#xff0c;也是实现提质增效的办公效果的有力武器。作为一家专业研发低代码技术平台的服务商&#xff0c;流辰信息的IBPS在很多行业领域中得到了大家的认可和喜爱&#xff0c;其中&#xff0c;工作流拖拽功能也是IBPS的主要功…

基于Springboot的计算机知识竞赛网站(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的计算机知识竞赛网站&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结…

【严格递增】2972统计移除递增子数组的数目 II

作者推荐 动态规划的时间复杂度优化 本文涉及知识点 严格递增 子数组 LeetCode2972. 统计移除递增子数组的数目 II 给你一个下标从 0 开始的 正 整数数组 nums 。 如果 nums 的一个子数组满足&#xff1a;移除这个子数组后剩余元素 严格递增 &#xff0c;那么我们称这个子…

【王道数据结构】【chapter7查找】【P309t10】

边那些一个递归算法&#xff0c;在一棵有n个几点的、随机建立起来的二叉排序树上查找第k(1<k<n)小的元素并返回指向该节点的指针。要求算法的平均时间复杂度为O(log2n).二叉排序树的每个结点中除data,lchild,rchild等数据成员外&#xff0c;增加一个count成员&#xff0c…

贪心算法

贪心算法 例题1、股票买卖题目信息思路题解 2、货仓选址题目信息思路题解 3、糖果传递题目信息思路题解 4、雷达设备题目信息思路题解 例题 1、股票买卖 题目信息 思路 相邻两天&#xff0c;后>前&#xff0c;则交易一次 题解 #include <bits/stdc.h> #define en…

Ansible script 模块 该模块用于将本机的脚本在被管理端的机器上运行。Ansible服务执行本机脚本

目录 过程首先&#xff0c;我们写一个脚本&#xff0c;并给其加上执行权限直接运行命令来实现在被管理端执行该脚本验证错误演示 过程 该模块直接指定脚本的路径即可 首先&#xff0c;我们写一个脚本&#xff0c;并给其加上执行权限 vim /tmp/df.sh编辑脚本内容 这个脚本内容…

动态住宅IP vs 静态住宅IP,如何选择适合你的海外住宅IP?

随着数字时代的发展&#xff0c;网络已经成为了我们日常生活中不可或缺的一部分。在海外留学、旅游、工作或者进行电子商务等活动时&#xff0c;一个合适的住宅IP可以帮助我们保护个人隐私、确保网络连接的稳定性、提高在线服务的可靠性等。因此&#xff0c;选择适合自己的住宅…

【C++】树形关联式容器set、multiset、map和multimap的介绍与使用

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.关联式容器 2.键…

【DDD】学习笔记-领域驱动设计体系

从统一语言到限界上下文&#xff0c;从限界上下文到上下文映射&#xff0c;从领域分析建模到领域设计建模&#xff0c;再从领域设计建模到领域实现建模&#xff0c;我将软件架构设计、面向对象设计、场景驱动设计和测试驱动开发有机地融合起来&#xff0c;贯穿于领域驱动设计的…

Python炒股自动化(2):获取股票实时数据和历史数据

如果你是一位大佬&#xff0c;看我前面的分享即可&#xff0c;相信你有自己的思路&#xff0c;或者已经有了成熟的策略&#xff0c;你需要的只是API接口来实现你的想法&#xff0c;前面的分享是你需要的&#xff0c;这些是给刚开始接触程序交易的朋友分享的。 前面发了股票程序…

如何使用Sora?Sora 介绍和注册使用教程

一、Sora 是什么&#xff1f; 2024年2月16日&#xff0c;OpenAI 在其官网上面正式宣布推出文本生成视频的大模型 Sora: Sora Sora能够根据简单的文本描述&#xff0c;生成高达60秒的高质量视频&#xff0c;使得视频创作变得前所未有的简单和高效。 和之前的文生视频模型&…

SpringCloud--Nacos解析

一、Nacos简介 Spring Cloud Alibaba Nacos是一个用于动态服务发现、配置管理和服务管理的平台&#xff0c;是阿里巴巴开源的一个项目&#xff0c;旨在简化微服务架构中的服务治理。Nacos 提供了一组简单易用的特性集&#xff0c;可以快速的实现动态服务发现、服务配置、服务元…