SpringBoot中事务失效的原因

news2024/9/20 16:43:43

SpringBoot中事务失效的原因

文章目录

  • SpringBoot中事务失效的原因
    • 一、事务方法非public修饰
    • 二、非事务方法调用事务方法
    • 三、事务方法的异常被捕获
    • 四、事务异常类型不对
    • 五、事务传播行为不对
    • 六、没有被Spring管理
      • 6.1、暴漏代理对象
      • 6.2、使用代理对象

常见的事务失效原因包括如下六个

一、事务方法非public修饰

由于Spring的事务是基于AOP的方式结合动态代理来实现的。因此事务方法一定要是public的,这样才能便于被Spring做事务的代理和增强。

而且,在Spring内部也会有一个 org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource类,去检查事务方法的修饰符:

	protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// Don't allow no-public methods as required.
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}
        // 省略
    }

二、非事务方法调用事务方法

@Service
public class OrderService {    
    public void createOrder(){
        // ... 准备订单数据
        // 生成订单并扣减库存insertOrderAndReduceStock();
    }    
    @Transactional
    public void insertOrderAndReduceStock(){
        // 生成订单insertOrder();
        // 扣减库存reduceStock();
    }   
}

可以看到,insertOrderAndReduceStock方法是一个事务方法,肯定会被Spring事务管理。Spring会给OrderService类生成一个动态代理对象,对insertOrderAndReduceStock方法做增加,实现事务效果。

但是现在createOrder方法是一个非事务方法,在其中调用了insertOrderAndReduceStock方法,这个调用其实隐含了一个this.的前缀。也就是说,这里相当于是直接调用原始的OrderService中的普通方法,而非被Spring代理对象的代理方法。那事务肯定就失效了!

三、事务方法的异常被捕获

异常被捕获了但是没有往外抛异常,所以事务没有发现方法中出现错误,所以也就没有回滚

在这段代码中,reduceStock方法内部直接捕获了Exception类型的异常,也就是说方法执行过程中即便出现了异常也不会向外抛出。

而Spring的事务管理就是要感知业务方法的异常,当捕获到异常后才会回滚事务。

现在事务被捕获,就会导致Spring无法感知事务异常,自然不会回滚,事务就失效了。

四、事务异常类型不对

@Transactional(rollbackFor = RuntimeException.class)
public void createOrder() throws IOException {
    // ... 
    // 准备订单数据
    // 生成订单insertOrder();
    // 扣减库存reduceStock();
    throw new IOException();
}

在这里插入图片描述

Spring的事务管理默认感知的异常类型是RuntimeException,当事务方法内部抛出了一个IOException时,不会被Spring捕获,因此就不会触发事务回滚,事务就失效了。

因此,当我们的业务中会抛出RuntimeException以外的异常时,应该通过@Transactional注解中的rollbackFor属性来指定异常类型:

@Transactional(rollbackFor = Exception.class)

五、事务传播行为不对

@Transactional
public void createOrder(){
    // 生成订单insertOrder();
    // 扣减库存reduceStock();
    throw new RuntimeException("业务异常");
}
@Transactional  // 默认的是如果当前没有事务,自己创建事务,如果有事务则加入
public void insertOrder() {

}
// 不管当前方法所在方法有没有都开启一个事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void reduceStock() {}

在示例代码中,事务的入口是createOrder()方法,会开启一个事务,可以成为外部事务。在createOrder()方法内部又调用了insertOrder()方法和reduceStock()方法。这两个都是事务方法。

不过,reduceStock()方法的事务传播行为是REQUIRES_NEW,这会导致在进入reduceStock()方法时会创建一个新的事务,可以成为子事务。insertOrder()则是默认,因此会与createOrder()合并事务。

因此,当createOrder方法最后抛出异常时,只会导致insertOrder方法回滚,而不会导致reduceStock方法回滚,因为reduceStock是一个独立事务。

所以,一定要慎用传播行为,注意外部事务与内部事务之间的关系。

六、没有被Spring管理

即当前类没有被SpringBoot扫描

第二种事务失效的解决方案:

上面的问题在于非事务方法中调用事务方法其中隐含了一个this.的前缀, 虽然当前方法的事务也被代理类生成了,但是因为默认关键字的原因,调用的还是原来的是没有事务的方法.

所以我们现在要做的就是要找到被代理之后的类,然后再在方法中调用该方法

6.1、暴漏代理对象

在启动类上添加注解,暴露代理对象:

@EnableAspectJAutoProxy(exposeProxy = true)

6.2、使用代理对象

通过AopContext拿到当前类的代理对象,然后调用对应方法

IUserCouponService userCouponService = (IUserCouponService) AopContext.currentProxy();
userCouponService.insertCouponAndCheck(userId, coupon, null);

注意:何时会产生代理对象?只有代理对象在调用方法的时候才会将当前代理对象暴漏在当前线程中

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

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

相关文章

《Flask Web 开发指南 pt.2》

在编写 Flask 程序的时候&#xff0c;你需要注意你的程序文件不要命名为 flask.py&#xff0c;建议命名为 app.py 或者 wsgi.py 但如果你的程序不是叫 app.py 或者 wsgi.py&#xff0c;那么你就需要设置环境变量 FLASK_APP 的值为程序名字 设置环境变量有两种方法&#xff0c;在…

聚观早报 | 腾讯字节等企业驰援防汛救灾;新能源车7月销量单出炉

【聚观365】8月4日消息 腾讯字节等企业驰援防汛救灾新能源车7月销量成绩单出炉Model Y等车型低温续航衰减严重华为Mate60系列猜想图曝光支付宝做短视频引来羊毛党 腾讯字节等企业驰援防汛救灾 近日&#xff0c;京津冀地区遭遇极端降雨天气&#xff0c;引发洪涝和地质灾害&…

智能仪表板DevExpress Dashboard v23.1亮点 - 增强对自定义导出的支持

DevExpress Dashboard v23.1版本增强了自定义导出到Excel的功能等&#xff0c;欢迎下载最新版本体验&#xff01; DevExpress Dashboard v23.1正式版下载(Q技术交流&#xff1a;523159565&#xff09; 所有平台 导出自定义仪表板项目到Excel 用户现在可以在WinForms和Web应…

吴新宙「跳槽」背后,是英伟达全栈智能汽车方案的「野心」

8月2号晚&#xff0c;小鹏汽车CEO何小鹏发文&#xff1a;因家庭和多方面的原因&#xff0c;小鹏汽车自动驾驶副总裁吴新宙将离开公司。同时也确定了吴新宙下一站&#xff1a;知名公司&#xff08;英伟达&#xff09;最高等级华人高管。 事实上&#xff0c;在过去的五年时间里&a…

科技引领,教育革新|EasyV助力数字孪生智慧教育建设!

数字孪生校园是以物联网、大数据、云计算、人工智能、三维可视化等新型数字化技术为基础&#xff0c;构建的数智校园的“大脑”。对校园的人、车、资产设施、各业务系统进行全联接&#xff0c;实现数据全融合、状态全可视、业务全可管、事件全可控&#xff0c;使校园更安全、更…

微信认证申请流程(媒体类型)

第一步&#xff1a;登录微信公众平台->设置->微信认证->开通 第二步&#xff1a;同意协议&#xff1a;签署《微信公众平台认证服务协议》 第三步&#xff1a;验证管理员 第四步&#xff1a;选择认证类型及填写认证资料 选择认证类型及上传申请公函 媒体资质信息 对公…

Gradle-02:问题Plugin with id ‘maven‘ not found

1. 背景 在一次使用 Gradle 构建自己项目&#xff0c;完事&#xff0c;需要上传到本地 Maven 仓库&#xff0c;因为事先并不清楚 apply plugin: maven 插件已经被 Gradle 移除&#xff0c;找了一圈&#xff0c;才找到解决方案。 2. 原因 apply plugin: maven def localRepo f…

Docker实战-关于Docker镜像的相关操作(一)

导语   镜像&#xff0c;Docker中三大核心概念之一&#xff0c;并且在运行Docker容器之前需要本地存储对应的镜像。那么下面我们就来介绍一下在Docker中如何使用镜像。 如何获取镜像&#xff1f; 镜像作为容器运行的前提条件&#xff0c;在Docker Hub上提供了各种各样的开放的…

项目进度管理软件可以解决哪些难题?

项目进度管理是在项目实施过程中&#xff0c;对各阶段的进展程度和项目最终完成的期限所进行的管理。它以确保项目能在满足其时间约束条件的前提下实现其总体目标。 项目进度管理软件可以解决以下难题&#xff1a; 一、进度跟踪 如果没有完善的进度计划&#xff0c;项目很难…

【计算机视觉 | Kaggle】飞机凝结轨迹识别 Baseline 分享和解读(含源代码)

文章目录 一、导读二、比赛背景三、比赛任务四、比赛数据五、评价指标六、Baseline6.1 Training part6.2 Submission part 一、导读 比赛名称&#xff1a;Google Research - Identify Contrails to Reduce Global Warming https://www.kaggle.com/competitions/google-researc…

一、单片机_RTOS_架构

1、RTOS的概念 RTOS是实时操作系统&#xff08;Real-Time Operating System&#xff09;的缩写。它是一种专门为实时应用程序设计的操作系统&#xff0c;具有实时性、高可靠性和紧凑性等特性。RTOS可以在嵌入式系统、工业自动化、航空航天、科学仪器等领域应用&#xff0c;主要…

HTML 基础标签

前言 当今互联网时代&#xff0c;网页是我们获取信息、交流和展示自己的重要渠道之一。而HTML&#xff08;超文本标记语言&#xff09;作为构建网页的基础&#xff0c;学习掌握HTML标签成为了必不可少的技能。 标题标签 <h1>~<h6>&#xff1a;这是用来定义标题的…

基于arcFace+faiss开发构建人脸识别系统

在上一篇博文《基于facenetfaiss开发构建人脸识别系统》中&#xff0c;我们实践了基于facenet和faiss的人脸识别系统开发&#xff0c;基于facenet后续提出来很多新的改进的网络模型&#xff0c;arcFace就是其中一款优秀的网络模型&#xff0c;本文的整体开发实现流程与前文相同…

vCenter Server Appliance(VCSA )7.0 部署指南

部署准备 1、下载VMware-VCSA-all-7.0.0-xxxx.iso文件&#xff0c;用虚拟光驱挂载或者解压运行&#xff0c;本地系统以win10拟光驱挂载为例&#xff0c;运行vcsa-ui-installer/win32/installer.exe。 2、选择“安装”&#xff0c;VCSA 7.0版本同时提供其他选项。 第一阶段 3、…

leetcode 35.搜索插入位置

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;搜索插入位置 ps&#xff1a; 题目给的是一个有序的数组&#xff0c;所以采用二分查找算法最优&#xff0c;只需要计算出如果目标值不存在则返回按顺序插入的位置&#xff0c;其实刚好是 left 位置。 代码&#xff1a; …

EtherCAT转Modbus网关连接TwinCAT3的配置方法

捷米JM-ECT-RTU 是自主研发的一款 ETHERCAT 从站功能的通讯网关。该产品主要功能是将 ETHERCAT 网络和 MODBUS-RTU 网络连接起来。 网关连接到 ETHERCAT 总线中做为从站使用&#xff0c;连接到 MODBUS-RTU 总线中做为主站或从站使用。 ​编辑切换为居中 添加图片注释&#x…

【计算机网络】NAT技术

文章目录 1. NAT技术简介2. 使用NAT技术转换IP的过程3. NAPT4. NAT技术的缺陷5. NAT和代理服务器 1. NAT技术简介 NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;技术&#xff0c;是解决IP地址不足的主要手段&#xff0c;并且能够有效避免外…

合合信息通过ISO/IEC国际标准双认证,为全球用户提供高合规标准AI服务

互联网、AI等技术的全球普及为人们提供便捷服务的同时&#xff0c;也带来了信息安全领域的诸多挑战。保护用户隐私及数据安全&#xff0c;是科技企业规范、健康发展的重心。近期&#xff0c;上海合合信息科技股份有限公司&#xff08;简称“合合信息”&#xff09;顺利通过国际…

量子纠错跨越式发展!Quantinuum科学家成功模拟氢分子

​ &#xff08;图片来源&#xff1a;网络&#xff09; 量子计算公司Quantinuum表示&#xff0c;它能在该公司的H1量子计算机上使用“容错法”来模拟氢分子。这是一种新的错误检测代码&#xff0c;能准确地进行模拟&#xff0c;通过在量子处理器上成功模拟化学分子&#xff0c;…

yolov5中的best.pt是如何确定的

在yolov5 的使用过程中几乎都会发现的问题&#xff1a; 训练结果有last.pt和best.pt , last.pt好理解&#xff0c;就是最后一个epoch的输出&#xff0c;但是best是啥意思&#xff1f;怎么才算best&#xff1f; 我们来一行行看train.py源码 追溯到./utils/metrics.py中的fitn…