使用@Transactional 注解下,事务失效的场景

前言

@Transactional是一种基于注解管理事务的方式,spring通过动态代理的方式为目标方法实现事务管理的增强。

@Transactional使用起来方便,但也需要注意引起@Transactional失效的场景,本文总结了七种情况,下面进行逐一分析。

一、异常被捕获后没有抛出

当异常被捕获后,并且没有再抛出,那么deleteUserA是不会回滚的。

@Transactional
public void deleteUser() {userMapper.deleteUserA();try {int i = 1 / 0;userMapper.deleteUserB();} catch (Exception e) {e.printStackTrace();}
}

二、抛出非运行时异常

Spring 事务,默认情况下只会回滚RuntimeException(运行时异常)和Error(错误),对于普通的 Exception(非运行时异常),它不会回滚。

@Transactional
public void deleteUser() throws MyException{userMapper.deleteUserA();try {int i = 1 / 0;userMapper.deleteUserB();} catch (Exception e) {throw new MyException();}
}

如果事务注解使用的是@Transactional(rollbackFor = Exception.class),那么抛出的是非RuntimeException类型异常是可以回滚的。

@Transactional(rollbackFor = Exception.class)

三、方法内部直接调用

这种场景很常见,方法A调用方法B,其中方法A未使用事务,而方法B使用了事务,此时方法B的事务是不生效的。例子如下,如果先调用deleteUser(),那么deleteUserA()是不会回滚的,其原因就是@Transactional根本没生成代理,如果直接调用deleteUser2()那么没问题,deleteUserA()会回滚。 

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public void deleteUser() throws MyException{deleteUser2();}@Transactionalpublic void deleteUser2() throws MyException{userMapper.deleteUserA();int i = 1 / 0;userMapper.deleteUserB();}
}

1. 修改调用方式,把当前类自己注入一下调用即可。

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;//自己注入自己@AutowiredUserService userService;public void deleteUser() throws MyException{userService.deleteUser2();}@Transactionalpublic void deleteUser2() throws MyException{userMapper.deleteUserA();int i = 1 / 0;userMapper.deleteUserB();}
}

2. 新加一个service方法,只需要新加一个 Service 方法,把 @Transactional 注解加到新 Service 方法上,把需要事务执行的代码移到新方法中

@Servcie
public class ServiceA {@Autowiredprvate ServiceB serviceB;public void save(User user) {queryData1();queryData2();serviceB.doSave(user);}}@Servciepublic class ServiceB {@Transactional(rollbackFor=Exception.class)public void doSave(User user) {addData1();updateData2();}}

四、新开启一个线程

如下的方式deleteUserA()也不会回滚,因为spring实现事务的原理是通过ThreadLocal把数据库连接绑定到当前线程中,新开启一个线程获取到的连接就不是同一个了。

@Transactional
public void deleteUser() throws MyException{userMapper.deleteUserA();try {//休眠1秒,保证deleteUserA先执行Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}new Thread(() -> {int i = 1/0;userMapper.deleteUserB();}).start();    
}

五、访问权限问题

java 的访问权限主要有四种:private、default、protected、public,它们的权限从左到右,依次变大。如果方法的访问权限被定义成了private,这样会导致事务失效,spring 要求被代理方法必须是public的。

@Transactional
private void deleteUser() throws MyException{userMapper.deleteUserA();int i = 1/0;userMapper.deleteUserB();
}

六、方法被final修饰

spring 事务底层使用了 aop,也就是通过 jdk 动态代理或者 cglib,帮我们生成了代理类,在代理类中实现的事务功能。但如果某个方法用 final 修饰了,那么在它的代理类中,就无法重写该方法,而添加事务功能。

@Transactional
public final void deleteUser() throws MyException{userMapper.deleteUserA();int i = 1/0;userMapper.deleteUserB();
}

注意:如果某个方法是 static修饰的,同样无法通过动态代理,变成事务方法。 

七、数据库本身不支持

在 mysql5 之前,默认的数据库引擎是myisam。它的缺点就是不支持事务,因此在mysql5之后,必须设置数据库引擎为InnoDB。

八、未被Spring管理

在我们平时开发过程中,有个细节很容易被忽略,即使用 spring 事务的前提是:对象要被 spring 管理,需要创建 bean 实例。通常情况下,我们通过 @Controller、@Service、@Component、@Repository 等注解,可以自动实现 bean 实例化和依赖注入的功能。如果有一天,你匆匆忙忙地开发了一个 Service 类,但忘了加 @Service 注解,那么该类不会交给 spring 管理,所以它内部的方法也不会生成事务。

九、事务传播属性设置错误

我们在使用@Transactional注解时,是可以指定propagation参数的。
该参数的作用是指定事务的传播特性,spring 目前支持 7 种传播特性:

REQUIRED 如果当前上下文中存在事务,则加入该事务,如果不存在事务,则创建一个事务,这是默认的传播属性值。
SUPPORTS 如果当前上下文中存在事务,则支持事务加入事务,如果不存在事务,则使用非事务的方式执行。
MANDATORY 当前上下文中必须存在事务,否则抛出异常。
REQUIRES_NEW 每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。
NOT_SUPPORTED 如果当前上下文中存在事务,则挂起当前事务,然后新的方法在没有事务的环境中执行。
NEVER 如果当前上下文中存在事务,则抛出异常,否则在无事务环境上执行代码。
NESTED 如果当前上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。
目前只有这三种传播特性才会创建新事务:REQUIRED,REQUIRES_NEW,NESTED。设置其他传播特性都不会创建事务。

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

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

相关文章

【面试必看】Java并发

并发 1. 线程 1. 线程vs进程 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。 系统运行一个程序即是一个进程从创建,运行到消亡的过程。在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进…

ChaosMeta V0.7.0 版本发布 进入CNCF混沌工程全景图

混沌工程 ChaosMeta 的全新版本 V0.7.0 现已正式发布!该版本包含了许多新特性和增强功能,在编排界面提供了多集群管理,在代码层面支持多命令下发通道的选择。另外由蚂蚁集团发起的ChaosMeta于北京时间2024年1月10日正式进入CNCF混沌工程全景图…

20232906 2023-2024-2 《网络与系统攻防技术》第十一次作业

20232906 2023-2024-2 《网络与系统攻防技术》第十一次作业 1.实验内容 一、web浏览器渗透攻击 任务:使用攻击机和Windows靶机进行浏览器渗透攻击实验,体验网页木马构造及实施浏览器攻击的实际过程。 二、取证分析实践—网页木马攻击场景分析 ①首先你…

07_Servlet

Servlet 一 Servlet简介 1.1 动态资源和静态资源 静态资源 无需在程序运行时通过代码运行生成的资源,在程序运行之前就写好的资源. 例如:html css js img ,音频文件和视频文件 动态资源 需要在程序运行时通过代码运行生成的资源,在程序运行之前无法确定的数据,运行时动态生成…

转行一年了

关注、星标公众号,直达精彩内容 ID:技术让梦想更伟大 整理:李肖遥 来公司一年了。 说是转行其实还是在半导体行业,熟悉我的朋友知道 ,我在18年开始进入半导体行业,那个时候想着行业很重要,站对了…

【前端三剑客之JS】详解JS

1. JS的引入方式 (1). 内部脚本方式引入 在页面上,通过一对script标签引入js代码.script代码放置位置有一定随意性,一般放在head标签中. (2).外部脚本方式引入. 内部脚本只能在当前页面中使用,代码复用度不高.可以将脚本放在单独的js文件…

HG/T 6088-2022 透水道路用涂料检测

透水混凝土是指由水泥、矿物掺合料、骨料、外加剂及水等主要材料经拌合形成的,具有透水功能的混凝土材料,用于其表面的涂料称为透水道路用涂料。 HG/T 6088-2022透水道路用涂料检测项目: 测试指标 测试方法 有害物质限量 GB 38468 在容器…

io.net 是什么,DePIN(去中心化物理基础设施网络)

目录 io.net 是什么 io.net去中心化原理 DePIN(去中心化物理基础设施网络)

气泡水位计的安装方法详解(二)

气泡水位计的安装方法详解(二) 产品简介 气泡式水位计ZL-BWL-013是一款适用于水文、水利信息化建设领域的新一代水位测量类设备,产品执行GB/T 11828.2-2022标准。ZL-BWL-013气泡水位计,具有安装方便、易于操作,高精度…

算法刷题day54:搜索(一)

目录 引言一、池塘计数二、城堡问题三、山峰和山谷四、迷宫问题五、武士风度的牛六、抓住那头牛七、矩阵距离八、魔板 引言 针对于蓝桥杯,搜索问题还是非常之重要的,在省赛前深知暴搜的重要性,所以提前先把提高课的搜索一章给看了&#xff0…

odoo10 编写图片上传接口(获取外部访问链接)

首先你需要一个模型 class Vehicle(models.Model):_name vehicleimage fields.Binary(string"图片", attachmentTrue)编写图片访问接口 http.route(/vehicle/image/<int:vehicle_id>, typehttp, authpublic)def vehicle_image(self, vehicle_id, **kwargs)…

分布式锁的原理和实现(Go)

文章目录 为什么需要分布式锁&#xff1f;go语言分布式锁的实现Redis自己的实现红锁是什么别人的带红锁的实现 etcdzk的实现 为什么需要分布式锁&#xff1f; 保证分布式系统并发请求或不同服务实例操作共享资源的安全性&#xff0c;通过一种协调机制来保证在同一时刻只有一个…

设计模式17——模板方法模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用&#xff0c;主要是下面的UML图可以起到大作用&#xff0c;在你学习过一遍以后可能会遗忘&#xff0c;忘记了不要紧&#xff0c;只要看一眼UML图就能想起来了。同时也请大家多多指教。 模板方法模式&#xff08;Temp…

阿里云Linux 3.2104 LTS 64位安装SVN服务器

直接按步骤 yum install subversion 写y就行 主要是看看安装了那些文件 rpm -ql subversion 主要是为了创建版本库而准备&#xff0c;这个能一遍创建就一遍创建&#xff0c;不行就逐个创建。能创就忽略下面两个mkdir步骤。 mkdir /home/svn/groupRepos 根据新建目录作为版本…

LeetCode第131场双周赛C++题解

3158.求出出现两次数字的XOR值 给你一个数组 nums &#xff0c;数组中的数字 要么 出现一次&#xff0c;要么 出现两次。 请你返回数组中所有出现两次数字的按位 XOR 值&#xff0c;如果没有数字出现过两次&#xff0c;返回 0 。 示例 1&#xff1a; 输入&#xff1a;nums …

程序中的网络地址等敏感信息,从网络安全的角度,应该怎么配置

从网络安全的角度来看&#xff0c;配置IP信息需要谨慎处理&#xff0c;以防止敏感信息泄露和系统受到攻击。以下是一些建议和最佳实践&#xff1a; 1. 使用环境变量或配置管理工具 环境变量 将IP地址等敏感信息存储在环境变量中&#xff0c;而不是硬编码在代码里。这有助于确…

业务实战————Uibot6.0 .1多页面商品信息抓取RPA机器人

前言 【案例描述】 鲜果记水果店计划在淘宝电商平台上开设一家新店&#xff0c;小微是该企业运营部分的运营专员&#xff0c;主要负责公司商品上架和管理的工作。 公司计划在开店的新品促销活动中增加水果品类红富士苹果。小微需在商品上架前了解目前平台中销量前列的红富士苹…

C#面:死锁的必要条件是什么?怎么克服?

C#中的死锁是指两个或多个线程互相等待对方释放资源&#xff0c;导致程序无法继续执行的情况。 死锁的必要条件&#xff1a; 互斥条件&#xff1a;至少有一个资源被设置为只能被一个线程占用。请求与保持条件&#xff1a;一个线程在持有资源的同时又请求其他线程占有的资源。…

SpringBootTest测试框架一

为了方便开发,对数据进行mock处理,形成文件,只修改文件内容达到mock指定数据的目的 1、定义测试模式 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface TestModel {TestModelEnum value() default TestModelEnum.LOCAL_PRIOR;String…

数字水印 | 离散余弦变换 DCT 基本原理及 Python 代码实现

目录 1 基本原理2 代码实现3 图像压缩 1 基本原理 参考博客&#xff1a;https://www.cnblogs.com/zxporz/p/16072580.html D C T \mathsf{DCT} DCT 全称为 D i s c r e t e C o s i n e T r a n s f o r m \mathsf{Discrete\ Cosine\ Transform} Discrete Cosine Transfo…