Spring事务与事务传播

在这里插入图片描述

文章目录

  • 一、什么是事务?
  • 二、Spring事务实现
    • 编程式事务
    • 声明式事务
  • 三、@Transactional的使用
    • 参数作用
    • Spring事务的隔离级别
    • 事务失效的场景
    • @Transactional工作原理
  • 四、Spring事务传播机制
    • Spring有哪些事务传播机制?

一、什么是事务?

事务:事务是一组操作的集合,是不可分割的基本单位,要么全部成功,要么全部失败
我们在MySQL中使用事务有三步操作:开启事务,提交事务,回滚事务

-- 开启事务
start transaction;-- 执行具体业务-- 提交事务
commit;-- 回滚事务
rollback

事务的四大特性(ACID): 原子性、一致性、持久性、隔离性
原子性(Atomicity):一个事务的操作,要么全部完成,要么全部不完成
一致性(Consistency):事务开始之前和事务结束之后,数据库的完整性没有被破坏
持久性(Isolation):事务提交后,对数据的修改就是永久的
隔离性(Durability):数据库允许多个并发事务同时对其数据读写和修改的能力,隔离性可以防止多个事务并发执行时导致的数据不一致
隔离级别是可以设置的

事务的隔离级别: 在数据库中,多个事务并发执行时,各个事务之间是相互隔离的,每个事务之间都不能相互干扰。为了保证并发事务的正确性和一致性,数据库管理系统(DBMS)提供了四种事务隔离级别,分别为读未提交、读已提交、可重复读和串行化。

读未提交(Read Uncommitted)
在该隔离级别下,一个事务可以读取另一个事务尚未提交的数据,不仅如此,它可能还会读到一些脏数据(Dirty Read)。在该级别下,数据的一致性和完整性得不到保障,不推荐使用。

读已提交(Read Committed)
在该隔离级别下,一个事务只能读取另一个事务已经提交的数据,避免了脏读的问题,但是可能会出现不可重复读(Non-Repeatable Read)的问题。即同一事务中,多次读取同一数据可能会得到不同的结果,因为其他事务可能在两次读取之间提交了修改。

可重复读(Repeatable Read)
在该隔离级别下,一个事务在执行期间多次读取同一数据时,能够保证所读取的数据一定是事务开始时的状态,避免了不可重复读的问题,但是可能会出现幻读(Phantom Read)问题,即两次查询间新增数据的影响。

串行化(Serializable)
在该隔离级别下,所有事务串行执行,避免了脏读、不可重复读和幻读的问题,但是实际应用中可能会导致性能严重下降,因此该级别一般只在特殊情况下使用。

默认隔离级别为REPEATABLE READ
在这里插入图片描述

我们可以使用以下SQL查询全局事务隔离级别和当前连接的事务隔离级别:

select @@global.tx_isolation,@@tx_isolation;

在这里插入图片描述

二、Spring事务实现

Spring中的事务分为两类:
1.编程式事务(手动操作)
2.声明式事务(自动提交事务)

编程式事务

SpringBoot内置了两个对象,DataSourceTransactionManager用来获取事务(开启事务、提交事务、回滚事务)。TransactionDefinition是事务的属性,在获取事务时,需要将TransactionDefinition传递进去获取一个TransactionStatus

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate DataSourceTransactionManager transactionManager;@Autowiredprivate TransactionDefinition transactionDefinition;@RequestMapping("/del")public int del(Integer id) {if(id != null && id > 0) {//开启事务TransactionStatus transactionStatus =transactionManager.getTransaction(transactionDefinition);//删除用户业务操作int result = userService.del(id);System.out.println("删除了: " + result);// 提交事务/回滚事务
//            transactionManager.commit(transactionStatus); //提交事务transactionManager.rollback(transactionStatus); //回滚事务}return 0;}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
数据库原始数据:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里显示操作成功,我们来看看我们数据库数据发生变化了没
在这里插入图片描述
我们可以发现,事务成功的进行了回滚,但是这样的方式太繁琐了,我们来学习更简单的声明式事务

声明式事务

声明式事务我们只需要在方法上@Transactional注解就可以实现,无需手动进行开启事务和提交事务,进入方法自动开启,执行完毕自动提交,发生异常后会自动回滚事务

@RestController
@RequestMapping("/user2")
public class UserController2 {@Autowiredprivate UserService userService;@Transactional@RequestMapping("/del")public int del(Integer id) {if(id == null || id <= 0) {return 0;}return userService.del(id);}
}

这种是没有异常的异常,我们会进行commit,我们目前数据库数据:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

我们可以发现成功的删除了数据库的一条数据:
在这里插入图片描述
我们来在业务中加上一段异常代码:

@RestController
@RequestMapping("/user2")
public class UserController2 {@Autowiredprivate UserService userService;@Transactional@RequestMapping("/del")public int del(Integer id) {if(id == null || id <= 0) {return 0;}int result = userService.del(id);int n = 1 / 0; //异常业务return result;}
}

我们再来进行删除操作:
在这里插入图片描述

在这里插入图片描述
我们可以看到我们的控制台信息,成功的进行了删除操作
在这里插入图片描述
同时报了一个算术异常
在这里插入图片描述
我们查看数据库信息,发现当发生异常时会自动进行回滚操作。

三、@Transactional的使用

@Transactional的作用范围:@Transactional既可以用来修饰方法也可以用来修饰类
1.修饰方法:只能应用到public方法上,否则不生效,推荐用法
2.修饰类:表明该注解对所有的public方法都生效

参数作用

我们可以通过设置@Transactional的一些参数来决定事务的一些具体的功能
在这里插入图片描述

Spring事务的隔离级别

Spring的事务隔离级别是有以下5种的
在这里插入图片描述
1.DEFAULT:使用底层数据库默认的隔离级别。
2.READ_UNCOMMITTED:允许读取还未提交的数据,会出现脏读、不可重复读和幻读等问题。
3.READ_COMMITTED:只能读取已经提交的数据,避免了脏读的问题,但是可能出现不可重复读和幻读的问题。
4.REPEATABLE_READ:保证同一事务中多次读取同一记录结果是一致的,避免了脏读和不可重复读的问题,但是仍然可能出现幻读的问题。
5.SERIALIZABLE:最高的隔离级别,保证事务串行执行,避免了脏读、不可重复读和幻读等问题,但是影响系统性能。

默认情况下,Spring 会使用底层数据库的默认隔离级别,通常是READ_COMMITTED 级别。可以通过事务管理器的 setDefaultTransactionIsolation() 方法或在事务注解中使用 isolation 属性来设置隔离级别,例如:

@Transactional(isolation = Isolation.DEFAULT)@RequestMapping("/del")public int del(Integer id) {}

在这里插入图片描述

在这里插入图片描述

事务失效的场景

常见的事务失效场景有以下三种:
1.异常捕获处理: @Transactional 在异常被捕获的情况下,不会进行事务自动回滚
在这里插入图片描述
我们进行操作之前的数据库数据,我们进行try,catch处理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们发现程序抛出了异常,但并没有进行回滚操作
在这里插入图片描述
原因:事务通知只有自己捕捉到了目标抛出的异常,才能进行后续的回滚操作,如果目标自己处理掉了异常,事务无法知悉

解决方案: 在catch块中添加throw new RuntimeException(e)抛出
在这里插入图片描述
我们将数据恢复
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们来进行操作时,进行了回滚操作

2.抛出检查异常:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们的事务未进行回滚操作
原因:Spring默认值只会回滚非检查异常

解决方案: 配置rollbackFor属性
在这里插入图片描述
在这里插入图片描述
在进行操作时,事务成功的进行了回滚操作

3.非public方法导致的事务失效:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
事务没有进行回滚操作
原因:Spring为方法创建代理,添加事务通知、前提条件都是该方法为public

解决方案: 改为Public

@Transactional工作原理

@Transactional 是基于 AOP 实现的,AOP 又是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理,如果目标对象没有实现了接口,会使用 CGLIB 动态代理。
@Transactional 在开始执行业务之前,通过代理先开启事务,在执行成功之后再提交事务。如果中途遇到异常,会进行回滚业务
在这里插入图片描述
@Transactional 具体执行细节如下图所示:
在这里插入图片描述

四、Spring事务传播机制

Spring事务传播机制定义了多个包含事务的方法,相互调用时
为什么需要事务传播机制?事务隔离级别不够用吗?
事务隔离级别是保证多个并发事务执行是可控的,而事务传播机制是保证一个事务在多个调用方法间是可控的。
事务隔离级别是为了解决多个事务同时调用一个数据库的问题:

在这里插入图片描述
事务传播机制是解决一个事务在多个方法中传递的问题:

在这里插入图片描述

Spring有哪些事务传播机制?

Spring 支持以下七种事务传播机制:

1.PROPAGATION_REQUIRED:默认值,如果当前存在一个事务,则加入该事务;否则新建一个事务。这是最常见的传播机制,也是大多数情况下使用的传播机制。如果外围方法已经启动了事务,那么内部方法就会在该事务中运行;如果外围方法尚未启动事务,则内部方法会启动一个新的事务。

2.PROPAGATION_REQUIRES_NEW:将当前事务挂起,开启一个新的事务进行执行。如果当前存在事务,则将当前事务挂起并启动一个新事务;如果当前没有事务,则开启一个新的独立事务。
3.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;否则以非事务方式继续运行。若外围方法有事务,则使用该事务;若外围方法没有事务,则直接执行。
4.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则将该事务挂起。若外围有事务,则将当前事务挂起,然后以非事务方式执行;若外围没有事务,则直接以非事务方式执行。
5.PROPAGATION_NEVER:表示当前方法不应该执行在事务上下文中。如果当前事务存在,则抛出异常。即表示当前方法不能够在事务环境中运行。
6.PROPAGATION_MANDATORY:当前方法必须在事务上下文中运行,否则抛出异常。要求当前环境中必须存在事务,否则会抛出异常。
7.PROPAGATION_NESTED:如果当前存在事务,则开启一个子事务进行执行;如果当前不存在事务,则新建一个事务进行执行。嵌套事务和普通事务的区别是,嵌套事务可以独立于外围事务进行提交或回滚,而不影响外围事务的状态。如果外围事务已经提交或回滚,则子事务也会被提交或回滚,但如果子事务发生异常而回滚,则外围事务可以选择回滚或不回滚。

事务传播机制可以分为以下三类:
在这里插入图片描述
我们可以更形象的看一下下述图来理解(别的大佬的图):
在这里插入图片描述

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

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

相关文章

mybatis分页中的报错

1 Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.NoSuchMethodException: com.github.pagehelper.BoundSqlInterceptor.<init>() 出错的原因就是上面的那句话 Error parsing SQL Mapper Configuration…

Mybatis分页方式及实现原理

一、mybatis的4种分页方式(物理分页、逻辑分页) 1、借助Sql语句Q进行分页(物理分页) 2、拦截器分页(物理分页)通过拦截器给sq语句末尾加Eimt语句来查询 3、借助 数组Q进行分页(逻辑分页) 4、RowBounds分页插件实现分页(逻辑分页) 二、mybatis分页的原理 mybatis分页原理是&…

Ora提示词版ChatGPT机器人

Ora可以自己创建一个ChatGPT机器人&#xff0c;可以设置自己的提示词例如我创建的AI佛祖https://ora.ai/aesthetic-red-nfa4/ai%E4%BD%9B%E7%A5%96 提示词 创建机器人的时候&#xff0c;需要设定自己的提示词&#xff0c;例如&#xff1a; 假设你是佛祖&#xff0c;名字叫做释迦…

mybatis分页查询插件

1.引入jar包 <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.3.0</version></dependency> 2.在mybatis的核心配置文件mybatis.xml中配置分页插件 3.使用pageHec publi…

Mybatis分页查询——四种传参方式

目录 相关导读 一、顺序传参 1. 持久层接口方法 2. UserMapper.xml映射文件新增标签 3. 新增测试方法 4. 运行结果 二、param传参 1. 持久层接口方法 2. UserMapper.xml映射文件新增标签 3. 新增测试方法 4. 运行结果 三、自定义POJO类传参 1. 自定义POJO类 2. 持…

MyBatis分页插件

目录 分页插件 Mybatis插件典型适用场景 实现思考 第一个问题 第二个问题 自定义分页插件 分页插件使用 添加pom依赖 插件注册 调用 代理和拦截是怎么实现的 PageHelper 原理 分页插件 MyBatis 通过提供插件机制&#xff0c;让我们可以根据自己的需要去增强MyBati…

Mybatis——分页

1.为什么要分页&#xff1f; 减少数据的处理量使用Limit分页 select * from user limit startIndex,pageSize;使用Mybatis实现分页&#xff0c;核心SQL 1.数据库文件-db.properties drivercom.mysql.jdbc.Driver urljdbc:mysql://localhost:3306/mybatis?useSSLfalse&…

Mybatis实现分页的三种方式

文章目录 1、Limit实现分页2、RowBounds分页&#xff08;不建议使用&#xff09;3、MyBatis分页插件PageHelper&#xff08;了解即可&#xff09; 1、Limit实现分页 sql语句 SELECT * from user limit startIndex,pageSize简单示例&#xff1a; user表 查询一&#xff1a;从第…

Mybatis的四种分页方式详解

LIMIT关键字 mapper代码 select * from tb_user limit #{pageNo}, #{pageSize} 业务层直接调用 public List findByPageInfo(PageInfo info) { return userMapper.selectByPageInfo(info); } 3&#xff0c;优点 灵活性高&#xff0c;可优化空间大 mysql分页语句优化 4&…

mybatis实现分页的几种方式

本文目录 借助数组进行分页借助Sql语句进行分页拦截器分页RowBounds实现分页 借助数组进行分页 原理&#xff1a;进行数据库查询操作时&#xff0c;获取到数据库中所有满足条件的记录&#xff0c;保存在应用的临时数组中&#xff0c;再通过List的subList方法&#xff0c;获取到…

【分布式应用】ELK企业级日志分析系统

一、ELK 简介 ELK平台是一套完整的日志集中处理解决方案&#xff0c;将 ElasticSearch、Logstash 和 Kiabana 三个开源工具配合使用&#xff0c; 完成更强大的用户对日志的查询、排序、统计需求。 1.1 ELK各组件介绍 ElasticSearch&#xff1a; 是基于Lucene&#xff08;一个…

Rust每日一练(Leetday0016) 全排列I\II、旋转图像

目录 46. 全排列 Permutations &#x1f31f;&#x1f31f; 47. 全排列 II Permutations II &#x1f31f;&#x1f31f; 48. 旋转图像 Rotate Image &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专…

win10操作系统官网如何下载ios境像文件安装操作系统

1.打开官网 2.立即下载工具 3.正在准备进行工作 4.接收条款 5.根据需求选择安装合适的位置 6.等待创建成功 7.右键选择装载 8.双击安装setup.exe文件 8 使用微Pe安装过程中发现需要联网更新解决 winR 然后cmd 输入 OOBE\BYPASSNRO 9 或者关闭此进程 电脑不要插网线&#xff…

虚拟机系统iso镜像下载_如何下载正版系统镜像

许多网友想装系统&#xff0c;可是不会装(后期会推装系统的文章)&#xff0c;而且网上的系统有的装有全家桶&#xff0c;有的又有捆绑软件&#xff0c;严重的还有病毒。那么&#xff0c;在哪里去下载正版&#xff0c;安全的系统镜像呢 "MSDN&#xff0c;我告诉你"这个…

自定义IOS系统弹框

写在之前 系统的弹框虽然很好看&#xff0c;但是有时候无法完全满足UI设计的需求&#xff0c;比如说中间要显示一个输入框&#xff0c;或者要放置一张图片&#xff0c;这里介绍一个很早之前的自定义弹框库&#xff0c;这个自定义弹框sdk写的很细致&#xff0c;定制性很强&…

华为vivo小米魅族oppo荣耀安卓手机刷IOS苹果系统

现在的刷机教程层出不穷&#xff0c;但是没有哪个大神可以开发出一款安卓刷IOS的工具&#xff0c;使得安卓手机或者安卓平板变成IOS苹果系统&#xff0c;这个工具除了可以刷安卓手机也可以刷安卓平板&#xff0c;网友实测&#xff0c;如果设备不支持的话软件会提醒不支持&#…

android高仿ios11系统,安卓仿ios11桌面全套文件

安卓手机想要苹果11的桌面的话&#xff0c;安卓仿ios11桌面全套文件app就可以帮您实现哦。安卓仿ios11桌面全套文件app是一款超级优质的手机桌面工具软件&#xff0c;平台上面拥有海量的壁纸资源&#xff0c;大家可以任意选取哦。 应用说明 修改负一屏效果 修改dock栏模糊度 修…

软件配置 | ios系统Clion下载、安装、配置环境

软件配置 软件配置 | ios系统Clion下载、安装、配置环境 软件配置下载、安装gClion 调试参考链接下载、安装调试 本文总结ios系统下Clion下载、安装、配置环境过程和可能碰到的问题。 因为是在私人电脑&#xff08;ios&#xff09;上配置的Clion&#xff0c;我还不太熟悉自己的…

iOS 13.0 至 13.7 平刷系统教程

来自 : 某QQ群分享文件&#xff0c;整理后发布 如侵权告知删除 关于 Succession 平刷插件信息&#xff1a; 插件&#xff1a;Succession 版本&#xff1a;1.4.15 开发者&#xff1a;Samg_is_a_Ninja 系统支持&#xff1a;iOS 10 至 13.7 用途&#xff1a;平刷当前系统 补充&am…

ios添加邮件收件服务器,iOS 系统邮件的基础使用

尽管有好多人的主力邮件是 Gmail,客户端的首选也是 Gmail,但是在国内的互联网环境中不可避免的要使用到本土的一些邮件服务。对于这些轻量级的服务我选择用系统自带的邮件应用进行统一的管理。本文主要讲解在系统自带邮件中,如何使用国内常用的邮件服务:如网易邮箱、QQ 邮箱…