Spring事务回滚核心源码解读

news2024/11/25 22:24:19

记一次Springboot事务超时不回滚的分析过程

在Springboot中,我用的xml进行事务管理,DataSourceTransactionManager作为事务管理器,配置了事务控制在Service层;在事务管理器中,配置了defaultTimeout事务超时时间为5秒,开始的认知里,如果事务执行超过5秒,Service层未执行完成,则认为会回滚事务
事务管理器的配置如下

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
        <property name="defaultTimeout" value="5"/>
    </bean>

事务控制在Service层配置

<aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.miso.infrastructure.asynctask.service.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>

开始测试

我的测试程序执行顺序是这样的:Controller->ServiceA->ServiceB->Dao
从Controller调用ServiceA开始,到ServiceA执行结束,是一个事务控制生命周期,如果在这个生命周期里,执行的时长超过事务管理器中配置的时间5秒,则事务回滚
在这里插入图片描述
为了能模拟延迟的效果,我在ServiceB调用Dao之前和之后,分别增加了Sleep的效果,让程序睡10秒
场景一:在调用Dao之前,增加让程序睡10秒

    public AsyncTaskEntity createAsyncTask(AsyncTaskEntity asyncTaskEntity) {
        Thread.sleep(10000);
        asyncTaskDao.createAsyncTask(asyncTaskEntity);
        return asyncTaskEntity;
    }

场景二:在调用Dao之后,增加让程序睡10秒

    public AsyncTaskEntity createAsyncTask(AsyncTaskEntity asyncTaskEntity) {
        asyncTaskDao.createAsyncTask(asyncTaskEntity);
        Thread.sleep(10000);
        return asyncTaskEntity;
    }

在我的第一认知里面,不管是场景一还是场景二,这两种都应该是超时回滚的,但实际测试结果出呼我所料,第一种场景事务回滚,而第二种场景没有回滚,第二种场景的即使超过了超时时间5秒,但是事务依然是提交的,在数据库中可以看到有新增的记录,是不是很意外,为什么事务执行时间超过了5秒,事务没有回滚,而是提交成功了呢?

开始分析

从这个报错的信息中,我们可以看到有一个抽象类ResourceHolderSupport,里面有个checkTransactionTimeout方法,这个方法里面扫了一个事务超时的异常
在这里插入图片描述
ResourceHolderSupport.checkTransactionTimeout源码如下,如果deadlineReached为true,则执行事务回滚,并抛事务超时异常

	private void checkTransactionTimeout(boolean deadlineReached) throws TransactionTimedOutException {
		if (deadlineReached) {
			setRollbackOnly();
			throw new TransactionTimedOutException("Transaction timed out: deadline was " + this.deadline);
		}
	}

从堆栈中可以看到,调用checkTransactionTimeout方法的是getTimeToLiveInMillis方法,ResourceHolderSupport.getTimeToLiveInMillis源码如下

	public long getTimeToLiveInMillis() throws TransactionTimedOutException{
		if (this.deadline == null) {
			throw new IllegalStateException("No timeout specified for this resource holder");
		}
		long timeToLive = this.deadline.getTime() - System.currentTimeMillis();
		checkTransactionTimeout(timeToLive <= 0);
		return timeToLive;
	}

从源码中可以看到,deadline的时间减去当前系统时间,如果小于0,则deadlineReached为true,事务进行回滚

那什么时候会调用ResourceHolderSupport.getTimeToLiveInMillis方法呢,从堆栈中可以看到整个的调用链如下:
在这里插入图片描述
在执行SimpleExecutor.prepareStatement方法时,会从Spring事务管理器中获取超时时间,最终调用到ResourceHolderSupport.getTimeToLiveInMillis
在这里插入图片描述
从这个调用链可以看出,Spring是在调用Dao的时候,去判断事务超时时间的,如果执行时间超过事务超时时间,则执行回滚,并抛出TransactionTimedOutException异常

因此到这里就可以解释了为什么上面 场景二:在调用Dao之后,增加让程序睡10秒不会回滚,因为dao层已经执行完成,后面不会进行超时判断了,除非在后面有另一个DAO的操作(前提是:同一个事务)

这里还有一个问题,ResourceHolderSupport.getTimeToLiveInMillis中的deadline.getTime()这个时间是在什么时候设置上的呢,我们注意到在ResourceHolderSupport中有个setTimeoutInMillis方法,这里有设置deadline的值,源码如下
在这里插入图片描述

那什么时候调用setTimeoutInMillis方法呢,在方法里打判断,查看堆栈信息,发现如下调用链
在这里插入图片描述

从调用链可以看出,Controll调用ServiceA之前,Spring框架会调用事务管理器DataSourceTransactionManager的doBegin方法开启事务,并在方法里面调用ResourceHolderSupport.setTimeoutInSeconds方法设置超时时间,之后才调用到ServiceA

因此在Controller调用ServiceA之前,Spring框架就会开启事务,并设置事务超时时间

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

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

相关文章

RK3588 - RKNN(Rockchip 神经处理单元)的逆向工程

本文翻译自https://jas-hacks.blogspot.com/2024/02/rk3588-reverse-engineering-rknn.html RK3588 NPU 的内部操作和功能主要隐藏在名为RKNPU2的闭源 SDK 中。由于对大型语言模型 (LLM) 的兴趣以及对transform模型最佳矩阵乘法的追求&#xff0c;想了解 RKNPU SDK 新引入的矩阵…

Jetpack Compose简介

文章目录 Jetpack Compose简介概述声明式UI和命令式UIJetpack Compose和Android View对比Compose API设计原则一切皆为函数组合优于继承单一数据源 Jetpack Compose和Android View关系使用ComposesetContent()源码ComposablePreview Jetpack Compose简介 概述 Jetpack Compos…

数据结构-二叉搜索树(BST)

目录 什么是二叉搜索树 二叉搜索树的特性 (1)顺序性 (2)局限性 二叉搜索树的应用 二叉搜索树的操作 (1)查找节点 (2)插入节点 (3)删除节点 (4)中序遍历 什么是二叉搜索树 如图所示&#xff0c;二叉搜索树&#xff08;binary search tree&#xff09;满足以下条件。…

Unity 递归实现数字不重复的排列组合

实现 private void Permutation(List<int> num, int leftIndex, List<string> strs) {if (leftIndex < num.Count){for (int rightIndex leftIndex; rightIndex < num.Count; rightIndex){Swap(num, leftIndex, rightIndex);Permutation(num, leftIndex 1…

【深度学习】【Lora训练1】StabelDiffusion,Lora训练过程,秋叶包,Linux,SDXL Lora训练

文章目录 一、环境搭建指南二、个性化安装流程三、启动应用四、打开web五、开始训练 19.27服务器 一、环境搭建指南 打造一个高效且友好的开发环境&#xff1a; 项目源码获取&#xff1a; 通过以下命令轻松克隆项目及所有子模块至您的Linux系统&#xff1a; git clone --recu…

workminer之dht通信部分

workminer是通过SSH爆破传播的挖矿木马&#xff0c;感染后会释放xmrig挖矿程序利用主机的CPU挖取北方门罗币。该样本能够执行特定的指令&#xff0c;指令保存在一个配置文件config中&#xff0c;config文件类似于xml文件&#xff0c;里面有要执行的指令和参数&#xff0c;样本中…

服务注册与发现Eureka、Zookeeper、Consul 三个注册中心的异同点(CAP理论)

Eureka Eureka是由Netflix开源的一个服务注册和发现组件&#xff0c;它主要用于构建高可用、分布式系统的基础设施中。Eureka的服务器端被称为Eureka Server&#xff0c;客户端则是那些需要注册的服务。Eureka具有以下特点&#xff1a; 高可用性&#xff1a;Eureka支持多节点…

小米汽车充电枪继电器信号

继电器型号&#xff1a; 参考链接 小米SU7&#xff0c;便捷充放电枪拆解 (qq.com)https://mp.weixin.qq.com/s?__bizMzU5ODA2NDg4OQ&mid2247486086&idx1&sn0dd4e7c9f7c72d10ea1c9f506faabfcc&chksmfe48a110c93f2806f6e000f6dc6b67569f6e504220bec14654ccce7d…

Linux网络开发基础知识

一个网络服务器的简单实现 项目需求 实现回声服务器的客户端/服务器程序&#xff0c;客户端通过网络连接到服务器&#xff0c;并发送任意一串英文信息&#xff0c;服务器端接收信息后&#xff0c; 将每个字符转换为大写并回送给客户端显示。 eoch_client.c #include <arpa/i…

Android双向认证配置过程

1&#xff08;可以绕过&#xff09;准备过程 为了让这个教程可以一直复用&#xff0c;打算直接写一个双向认证的APP作为素材。 工具&#xff1a; ●protecle&#xff08;签名文件转换&#xff09; ●keytool&#xff08;java自己就有&#xff09; ●openssl&#xff08;apache里…

前端canvas项目实战——在线图文编辑器(九):逻辑画布

目录 前言一、 效果展示二、 实现步骤1. 调整布局&#xff0c;最大化利用屏幕空间2. 添加逻辑画布3. 添加遮罩4. 居中显示逻辑画布5. 一个容易被忽视的bug点 三、Show u the code后记 前言 上一篇博文中&#xff0c;我们实现了一组通用的功能按钮&#xff1a;复制、删除、锁定…

LeetCode-hot100题解—Day5

原题链接&#xff1a;力扣热题-HOT100 我把刷题的顺序调整了一下&#xff0c;所以可以根据题号进行参考&#xff0c;题号和力扣上时对应的&#xff0c;那么接下来就开始刷题之旅吧~ 1-8题见LeetCode-hot100题解—Day1 9-16题见LeetCode-hot100题解—Day2 17-24题见LeetCode-hot…

httpClient提交报文中文乱码

httpClient提交中文乱码&#xff0c;ContentType类型application/json 指定提交参数的编码即可 StringEntity se new StringEntity(paramBody.toJSONString(),"UTF-8");se.setContentType("application/json");context.httpPost.setHeader("Cookie&…

Go-Zero从0到1实现微服务项目开发(二)

前言 书接上回&#xff0c;继续更新GoZero微服务实战系列文章。 上一篇被GoZero作者万总点赞了&#xff0c;更文动力倍增&#xff0c;也建议大家先看巧一篇&#xff0c;欢迎粉丝股东们三连支持一波&#xff1a;Go-zero微服务快速入门和最佳实践&#xff08;一&#xff09; 本…

Windows Server 2022 OVF, updated Apr 2024 (sysin) - VMware 虚拟机模板

Windows Server 2022 OVF, updated Apr 2024 (sysin) - VMware 虚拟机模板 2024 年 4 月版本更新&#xff0c;现在自动运行 sysprep&#xff0c;支持 ESXi Host Client 部署 请访问原文链接&#xff1a;Windows Server 2022 OVF, updated Apr 2024 (sysin) - VMware 虚拟机模…

从Kernel启动到Android系统整个过程源码分析

1、 第一阶段&#xff1a; 对于ARM的处理器&#xff0c;内核第一个启动的文件是arc/arm/kernel下面的head.S文件。当然arc/arm/boot/compress下面也有这个文件&#xff0c;这个文件和上面的文件略有不同&#xff0c;当要生成压缩的内核时zImage时&#xff0c;启动的是后者&…

企业如何保证内部传输文件使用的工具是安全的?

企业内部文件的频繁交换成为了日常运营不可或缺的一环。然而&#xff0c;随着数据量的爆炸式增长和网络攻击手段的日益复杂&#xff0c;内网文件传输的安全隐患也日益凸显&#xff0c;成为企业信息安全的薄弱环节。本文将探讨内网文件传输的安全风险、企业常用的防护措施。 内网…

《Fundamentals of Power Electronics》——Buck、Boost、Buck-Boost三个电路的CCM-DCM工作特性总结

Buck、Boost、Buck-Boost这三个电路的CCM-DCM工作特性总结如下表所示&#xff1a; Buck、Boost、Buck-Boost这三个电路工作在DCM模式下电压传输比的对比图如下所示&#xff1a; 由上图可知&#xff0c;Buck-Boost电路的工作特性是一条斜率为的直线&#xff0c;Buck电路和Boost电…

小长假来临,企业借助巡检系统做好安全巡查工作

节前节后是安全隐患事故多发期&#xff0c;小长假来了&#xff0c;企业面临着员工离岗、生产活动减少等特殊情况&#xff0c;这可能导致一些安全隐患被忽视。因此&#xff0c;借助巡检系统做好全面安全巡查工作显得尤为重要。巡检系统可以帮助企业实现巡检工作的规范化、标准化…

八_实验1:创建 VLAN 和划分端口

1、实验目的 通过本实验可以掌握&#xff1a; VLAN的概念。创建VLAN的方法。把交换机端口划分到VLAN中的方法。 2、实验​​​​​​拓扑 创建 VLAN 和划分端口的实验拓扑如下图所示。 图8-5 创建 VLAN 和划分端口的实验拓扑 3、实验步骤 &#xff08;1&#xff09;实验准…