Spring事务及事务失效的部分场景

2023-11-14

简介

spring 有五个事务隔离级别:ISOLATION_DEFAULT、ISOLATION_READ_UNCOMMITTED、ISOLATION_READ_COMMITTED、ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE

第一种是 Spring 默认使用 DB设置的事务隔离级别,后面四种事务隔离级别跟 Mysql 的事务隔离级别一致,下面就类比着 Mysql 的事务隔离级别,进行分析!!!

事务并发可能产生的问题释义

脏读 ( Dirty Read ):一个事务读取到另一个未提交事务修改过的数据

session B 开启一个事务,修改了 id = 1 的 name 数据,但是 session B 事务未提交;此时 另一个 session A 事务读取到 session B 修改但没提交的 name 数据,并返回了,然后 session B 事务回滚了,那么此刻 session A 读取到的数据是不存在的,那么这种现象是脏读。(读未提交–该事务隔离级别会出现)

不可重复读 (Non-Repeatable-Read) : 事务 A 中,多次读取同一条数据,此时事务 A 并没有结束,事务 B 对同一条数据进行了修改,事务 A 读取到 事务 B 修改后的数据,造成了 事务 A 多次读取的数据值不一致,这种现象就是不可重复读

session A 事务开启,读取到 id = 1 的 name 数据为武汉,session A 事务并未结束, session B 事务将 id = 1 的 name 数据修改为 温州,session A 事务读取 id =1 的 name 数据为温州;session B 事务将 id = 1 的 name 数据修改为杭州,sesssion A 事务读取 id = 1 的 name 数据为杭州;session B 事务每次修改后的数据,session A 事务都能读取到最新的数据,那么这种现象就是不可重复读。(读未提交,读已提交–两种事务隔离级别都可能会出现)

幻读 (Phantom) : 一个事务读取符合某些条件的数据, 该事务未结束,此时另一个事务插入了一些符合这些条件的新数据,这个事务再次根据这些条件读取数据时,能把另一个事务插入的数据也取出来,那么这种现象叫幻读

session A 事务开启,读取 id > 0 的 name 数据为武汉,session 事务 A 未结束;session B 事务开启,插入温州市数据;session A 事务再次读取 id > 0 的 name 数据,读取到武汉和温州时,这种现象就是幻读 (读未提交,读已提交,可重复读–三种隔离级别都可能出现)

事务隔离级别释义

DEFAULT:采用 DB 默认设置的事务隔离级别
READ_UNCOMMITTED:读未提交(会出现脏读,不可重复读,幻读)(隔离级别最低,并发性能最高)

session A 事务开启,更新 id = 1 的数据为温州;session B 的事务开启,读取到未提交事务 A 修改的数据;

READ_COMMITTED:读已提交(会出现不可重复读,幻读)

session A 事务开启,更新 id =1 的 name 数据,session B 事务开启,读取 id = 1 的 name 数据为 武汉;session A事务提交,session B 事务再次读取 id = 1 的name 数据为温州;也就是说 事务 B 只能读取到 事务 A 修改且提交的数据

REPEATABLE_READ:可重复读(会出现幻读)

session A 事务开启,更新 id = 1 的 name 名称为温州,此时 session B 事务开启,读取 id = 1 的数据为 武汉

session A 事务读取 id = 1 的 name 名称为温州;session A 事务提交;session B 事务提交;session B 事务再次读取 id = 1 的 name 名称为 温州;也就是说在可重复读隔离级别下,session B 事务读取 session A 事务修改后的值,需要 session A 事务修改数据且提交,session B 当前的事务也提交。

提问:为什么 session A事务修改数据,加了写锁,为什么别的事务还可以操作?因为 MVCC 多版本控制,有快照可以供其他事务读

SERIALIZABLE:可串行化(不会出现脏读、不可重复读,幻读)(隔离级别最高,并发性能最低)
1. 读读操作(不会阻塞,两个读操作互不影响)
2. 读写操作(会产生阻塞,读操作提交之后,写操作才会执行)
3. 写读操作(会阻塞,写操作提交之后,读操作才会执行)
4. 写写操作(会阻塞,前面的写操作提交之后,后面的写操作才会执行)

事务传播行为

在 Spring-tx 的 jar 包中, TransactionDefinition 接口定义了七种事务传播行为:

1. PROPAGATION_REQUIRED(Spring 默认设置)

​ 当前方法必须在一个具有事务的上下文中运行,如果调用端有事务在运行,那么被调用端将在该事务中运行,否则将重新开启一个事务( 如果被调用端发生异常,则调用端和被调用端事务都将回滚 )

2. PROPAGATION_SUPPORTS

​ 当前方法不必需要一个具有事务的上下文,但是上下文具有事务时,也可以在这个事务中运行

3. PROPAGATION_MANDATORY

​ 当前方法必须在一个事务中运行,不然会抛出异常

4. PROPAGATION_REQUIRES_NEW

​ 当前方法必须运行在它自己的事务中,如果一个新的事务将启动,而且如果有一个当前事务在运行的话,则当前事务( 方法 )在运行期被挂起,等待新事务提交或回滚才恢复执行

5. PROPAGATION_NOT_SUPPORTED

​ 当前方法不支持在事务中运行,总是以非事务的方式运行,如果有一个事务正在执行,当前方法将在运行期挂起,直到这个事务提交或回滚,才恢复执行

6. PROPAGATION_NEVER

​ 当前方法不支持在事务中运行,如果存在当前事务,将会抛出异常

7. PROPAGATION_NESTED

​ 如果当前方法存在一个事务正在执行,那么该方法应该运行在一个嵌套事务中,被嵌套的事务(子事务)可以独立于被封装的事务(父事务)之外提交或回滚。如果封装事务存在,并且外层事务抛出异常,事务回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则跟 PROPAGATION_REQUIRED 的传播机制一致

事务失效的场景

1. 没有走动态代理导致事务失效的场景
1.1 访问权限问题

Java 的访问权限,主要有四种:private、default、protected 、public 权限从左往右,依次变大,如果事务方法,使用错误的访问权限,事务就会出现问题,spring-tx 的 jar 包 中 AbstractFallbackTransactionAttributeSource#computeTransactionAttribute() 方法,事务方法必须是 public 关键字修饰的访问权限,否则会返回 null,事务就会失效,所以事务方法访问权限是 private ,default ,protected 关键字修饰时,Spring不会提供事务功能

1.2 使用 final 、static 关键字修饰

如果某个方法不想被子类重写,就需要用 final 关键字修饰,Spring 的事务是基于 AOP 实现的,如果使用 final 关键字,该方法将不会被重写,则无法通过动态代理,生成代理类,添加事务;static 关键字也无法使用动态代理,生成代理类,添加事务!

1.3 方法内部调用

同一个类中的方法,直接内部调用,会导致事务失效,因为 spring 的 事务是通过 aop 实现的,同一个类中的方法,直接调用,相当于通过 this 关键字直接调用方法,没有通过代理类,添加事务,故事务失效!可以通过 AopContext#currentProxy() 获取代理对象,使用事务!!!

@Servcie
public class ServiceA {

   public void save(User user) {
         queryData1();
         queryData2();
         ((ServiceA)AopContext.currentProxy()).doSave(user);
   }

   @Transactional(rollbackFor=Exception.class)
   public void doSave(User user) {
       addData1();
       updateData2();
    }
 }
1.4 没有被 Spring 管理

使用 Spring 的事务,需要Bean 对象被 Spring 管理。没有使用@Controller @Service @Reponsitory @Component @Bean 等注解,对象将不会被 Spring 管理,则事务不生效

2. 异常导致事务失效的场景
2.1 自己捕获异常

Spring 事务需要正常回滚,必须抛出 Spring 能正确处理的异常,如果没有异常抛出,则事务不会回滚

@Slf4j
@Service
public class UserService {
    
    @Transactional
    public void add(UserModel userModel) throws Exception {
        try {
             saveData(userModel);
             updateData(userModel);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}
2.2 手动抛出非(运行时异常(RuntimeException)或错误(Error))

如果代码捕获了异常,并手动抛出了异常:Exception ,对于普通的 Exception (非运行时异常),事务不会回滚

@Slf4j
@Service
public class UserService {
    
    @Transactional
    public void add(UserModel userModel) throws Exception {
        try {
             saveData(userModel);
             updateData(userModel);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new Exception(e);
        }
    }
}
2.3 自定义回滚异常

@Transactional 注解中的 rollbackFor 属性使用默认值,那么当程序抛出 Exception ,事务不会回滚,所以,一般需要设置 rollbackFor 的属性值为 Exception 或 Throwable

@Slf4j
@Service
public class UserService {
    
    @Transactional(rollbackFor = BusinessException.class)
    public void add(UserModel userModel) throws Exception {
       saveData(userModel);
       updateData(userModel);
    }
}
引用
  • https://developer.aliyun.com/article/743691
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring事务及事务失效的部分场景 的相关文章

随机推荐

  • 14. 函数返回值为引用?

    函数返回值可以是引用吗 当然可以 只是在函数返回引用的时候需要注意几点 以下给出讨论 函数在返回值的时候 会产生一个临时变量作为函数返回值的副本 而函数在返回引用的时候 不会产生副本 那么既然是引用 那么到底是引用谁呢 首先 我们知道要清楚
  • 解决dubbo注册zookepper服务IP乱入问题的三种方式

    最近做一个项目引入了dubbo zookepper的分布式服务治理框架 在应用的发布的时候出现一个怪问题 zookepper服务是起在开发服务器192 168 23 180上 本机起应用服务提供者注册到192 168 23 180上的dub
  • 第一课:k8s介绍安装

    第一课 k8s介绍安装 tags golang 2019尚硅谷 categories K8s 文章目录 第一课 k8s介绍安装 第一节 K8s发展流程 1 1 相关概念 1 2 K8s发展历史 1 3 K8s特点 1 4 课程架构 需要掌握
  • 【廖雪峰python入门笔记】list_倒序访问

    倒序访问list 我们还是用一个list按分数从高到低表示出班里的3个同学 L Adam Lisa Bart 这时 老师说 请分数最低的同学站出来 要写代码完成这个任务 我们可以先数一数这个 list 发现它包含3个元素 因此 最后一个元素
  • MySql中json类型数据的查询以及在MyBatis-Plus中的使用

    表结构和初始数据 新建表结构 CREATE TABLE json test id int NOT NULL AUTO INCREMENT roles json DEFAULT NULL COMMENT 角色 project json DEF
  • Java线程池中哪些事??

    需要提前把线程准备好 创建线程不是直接从系统申请 而是从池子里拿 等到线程不用了 也是还给池子 池子的目的是为了提高效率 线程的创建虽然比进程轻量 但是在频繁创建的情况下 开销也是不可忽略的 则希望还能进一步提高效率 那么 就需要用到线程池
  • gpio 上拉下拉

    每个gpio内部有三种状态 上拉 下拉 不拉 什么时候 需要选择上拉 下拉或不拉呢 1 如果是output 那个一般选择no pull 这样 引脚才能根据你的output数据 进行正确输出 2 如果是input 那么需要看具体应用的默认输入
  • printk函数的用法

    printk在内核源码中用来记录日志信息的函数 只能在内核源码范围内使用 用法和printf非常相似 printk函数主要做两件事情 第一件就是将信息记录到log中 而第二件事就是调用控制台驱动来将信息输出 1 日志级别 printk相比p
  • 设计模式(九)组合模式

    在数据结构中 有树这么一种结构 转换到设计模式中就是组合模式 组合模式的作用就是以统一的方式处理一组具有树形结构的对象 最典型的例子就是菜单项了 一个菜单下可能包括多个菜单项 每个菜单项都可能包含其他子菜单 下面我们来实现菜单项 由于每个菜
  • vector排序问题

    要对vector中的自定义类型进行排序 首先需要提供一个函数bool comp const Interval a const Interval b 来定义类型的排序准则 然后调用std sort intervals begin interv
  • linux下解压zip文件

    linux自带的unzip命令可以解压windows下的zip格式的压缩文件 unzip命令 语法 unzip 选项 压缩文件名 zip 各选项的含义分别为 x 文件列表 解压缩文件 但不包括指定的file文件 v 查看压缩文件目录 但不解
  • pycharm PyQt5报错 Process finished with exit code -1073740791 (0xC0000409) 解决方法

    在写python作业的时候他突然报错了 我觉得我是对的 想法没问题系列 界面也可以出来 是我想象中的样子 但是不能进行交互 所以我怀疑是环境问题或者是什么别的 反正不是我自身原因 蜜汁自信 然后我试了一下老师上课给的例子发现可以运行 我知道
  • GT1030和730哪个好?GT1030与GT730区别对比 (全文)

    对于显卡硬件厂商来说 当属NVIDIA可谓异常活跃 我们知道在游戏领域 N卡一直占据着绝大部分市场 旗下的显卡定位也非常明确 如最新的10系显卡 今年5月份NVIDIA低调发布了定位入门级显卡 GT1030 这款显卡上市之后立马引起了不少玩
  • android图片点击全屏显示,Android浏览图片,点击放大至全屏效果

    近期做一个项目类似于QQ空间 做到照片浏览的功能 对于QQ空间中点击图片放大至全屏 感觉效果非常赞 于是也做了个类似的效果 例如以下 我不知道QQ那个是怎么做的 我的思路例如以下 首先 从图片缩略界面跳转到图片详情页面 应该是从一个Acti
  • 概率论在实际生活的例子_概率论学习笔记

    一 从古典概型开始引入概率论的基本概念 古典概型 全称古典概率模型 也叫等可能模型 是人们最早研究的概率 也是学习概率论的起点 古典概型通过随机实验获得结果 而古典概率研究的问题有两个重要特点 结果有限 可能性一致 1 结果有限 指的是实验
  • C语言以字符形式读写文件

    一 字符读取函数 fgetc 一 函数介绍 fgetc 是 file get char 的缩写 意思是从指定的文件中读取一个字符 函数原型为 int fgetc FILE fp fp 为文件指针 fgetc 读取成功时返回读取到的字符 读取
  • Maven快速搭建GUI项目

    一 eclipse安装好maven插件 并将maven集成到eclipse之后 用maven的archetype 搭建好一个maven archetype queckstart项目的骨架 二 可执行jar文件分为两种 一种是可通过命令行ja
  • 【R语言】实验四 数据分析

    系列文章目录 实验一 R 语言数据结构 数据导入与数据处理 实验二 基本数据处理 实验三 数据可视化 实验四 数据分析 实验五 综合应用 实验数据 实验数据下载 1 hospital data 数据集 数据是关于一些医院的基础信息 数据包含
  • 如何降低APP卸载率?这里有七个方法

    如何降低APP卸载率 这里有七个方法 A A admin 2017 年 1 月 19 日 0 597 次浏览 业内资讯 APP卸载率 现在移动应用市场红海一片 获取用户越来越难 但据了解 更让开发者们为难的是 产品的高卸载率 高卸载率是用户
  • Spring事务及事务失效的部分场景

    简介 spring 有五个事务隔离级别 ISOLATION DEFAULT ISOLATION READ UNCOMMITTED ISOLATION READ COMMITTED ISOLATION REPEATABLE READ ISOL