Spring事务回滚核心源码解读

记一次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框架就会开启事务,并设置事务超时时间

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

云香印象终端自动化工具(监听农行收款云音箱)

项目成品 支持自动挂单✅完成监控收款云音箱✅完成卷烟盘点✅完成补单✅完成自动入库✅完成监控微信支付✅完成自动提交会员信息✅完成 用到的技术栈&#xff1a;PythonMQTT5.0PHP 云香印象终端自动收款工具 ​​​​​ 当顾客扫了三合一二维码且支付完成时&#xff0c;监控收到…

精酿啤酒:酿造工艺的自动化与智能化发展

随着科技的不断进步&#xff0c;自动化与智能化已成为啤酒酿造工艺的重要发展方向。Fendi Club啤酒紧跟时代潮流&#xff0c;积极推动酿造工艺的自动化与智能化发展&#xff0c;旨在提高生产效率、确保产品品质和满足市场需求。 Fendi Club啤酒引入自动化生产设备。他们采用自动…

Mybatis-plus 字段结果为NULL

问题 Mybatis-plus 字段结果为NULL 详细问题 笔者使用SpringBootMybatis-plus 进行项目开发。进行接口请求测试&#xff0c;在确定SQL语句没有问题的前提下&#xff0c;返回记录部分字段(譬如字段name)为空。 解决方案 修改Mybatis-plus中mapper的xml文件&#xff0c;使re…

CentOS7版本安装mysql

文章目录 1.安装mysql的前置条件2.清理原有的mysql数据库3.查看是否安装mariadb4.安装mysql依赖包5.解压缩mysql包6.安装目录赋权限&#xff08;注&#xff1a;R必须是大写&#xff09;7.创建MySQL组8.将mysql目录的权限授给mysql用户和mysql组9.创建mysql安装初始化配置文件10…

APP广告变现项目

我们提供的服务可以简化为以下几点&#xff1a; 我们将为您开发一款应用程序(APP)&#xff0c;该APP能够连接市场上的主要广告联盟平台。 我们将指导您完成整个“养机”流程&#xff0c;并确保您的单台设备每条广告能产生大约1元的收益。若您拥有10台设备&#xff0c;每日收益…

ElasticSearch搜索引擎中,在Kibana客户端使用命令的时候,千万不要加分号结尾

ElasticSearch搜索引擎中&#xff0c;在Kibana客户端使用命令的时候&#xff0c;千万不要加分号结尾 今天遇到了一个非常难发现的bug 由于经常写java代码&#xff0c;因此常常会在一句代码结尾之处写上一个分号&#xff0c;并且潜意识里觉得这就是非常正常的事情 不会有什么问…

c++的智能指针(5) -- weak_ptr

概述 我们在使用shared_ptr会出现以下的问题&#xff0c;会导致内存泄露。 代码1: 类内指针循环指向 #include <iostream> #include <memory>class B;class A { public:A() {std::cout << "Construct" << std::endl;}~A() {std::cout <…

鸿蒙入门11-DataPanel组件

数据面板组件 用于将多个数据的占比情况使用 占比图 进行展示 参数 参数形式 &#xff1a; DataPanel( options:{ values: number[], max?: number, type?: DataPanelType } ) 参数名 参数类型 是否必填 默认值 参数描述 values number[] 是 - 数据值列表 最大支持…

Android Studio的button点击事件

xml添加onClick调用方法 public class MainActivity extends AppCompatActivity {// 创建系统时间的文本控件TextView systemTimeTextView;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activit…

Springboot+Vue项目-基于Java+MySQL的海滨体育馆管理系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

Jmeter工具+ant+jenkins实现持续集成

jmeterantjenkins持续集成 一、下载并配置jmeter 首先下载jmeter工具&#xff0c;并配置好环境变量&#xff1b;参考&#xff1a; jmeter默认保存的是.jtl格式的文件&#xff0c;要设置一下bin/jmeter.properties,文件内容&#xff0c;保存jmeter.save.saveservice.output_f…

【linux】Bad owner or permissions on

在root用户下执行scp操作向另外一个节点拷贝文件时发生了如下错误&#xff1a; Bad owner or permissions on /etc/crypto-policies/back-ends/openssh.config 我们查看他的权限时发现它所链接的文件权限为777 解决方法就是&#xff1a; chmod 600 /etc/crypto-policies/back-e…

关于加强电力系统通信与电网调度自动化建设问题的规定

关于加强电力系统通信与电网调度自动化建设问题的规定 为了保障电力系统安全、经济、优质、可靠运行&#xff0c;必须加强电网调度管理和提高技术装备水平。根据当前电网技术装备状况&#xff0c;结合电力系统通信和电网调度自动化的特点&#xff0c;以及今后规划发展的要求&am…

Python基础知识—运算符和if语句(二)

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》 《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 1.输入和输出函数1.1输出函数1.2输入函数 2.常见运算符2.1赋值运算符2.2比较运算符2.3逻辑运算符2.4and逻辑与2.5or逻辑或2.6not逻…

Java后台开发的前置说明

1.知识点逻辑 一个部分 都是先挑重点知识点讲解 然后根据这些重点知识点去完成一个项目的开发 然后在到返回来解决这个部分其他细枝末节的知识点 2.软件开发的分工 我们大致可以将软件开发分成四块&#xff1a; 1.前端开发(比如开发电脑中的京东 htmlcssjavascript) 2.移动开…

Springboot3集成Web、RedisTemplate、Test和knife4j

本例将展示&#xff0c;如何在Springboot3中完成&#xff1a; Redis功能的Web接口实现构建Redis功能的单元测试knife4j自动化生成文档 Redis功能 Pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter…

【EdgeBox-8120AI-TX2】Ubuntu18.04 + ROS_ Melodic + 星秒PAVO2单线激光 雷达评测

大家好&#xff0c;我是虎哥&#xff0c;好久不见&#xff0c;最近这断时间出现了一点变故&#xff0c;开始自己创业&#xff0c;很多事需要忙&#xff0c;所以停更了大约大半年&#xff0c;最近一切已经理顺&#xff0c;所以我还是抽空继续我之前的FLAG&#xff0c;CSDN突破十…

Hadoop伪分布式平台搭建

搭建Hadoop伪分布式环境是在单台机器上模拟完整的Hadoop分布式系统&#xff0c;使得所有的Hadoop守护进程&#xff08;如NameNode、DataNode、ResourceManager、NodeManager等&#xff09;都在同一台机器上运行。这样可以在一台机器上体验Hadoop的分布式特性&#xff0c;适合学…

《AI极简经济学》|揭开AI面纱,普通人的机遇与挑战

《AI极简经济学》一书由经济学家阿杰伊阿格拉沃尔、乔舒亚甘斯和阿维戈德法布联袂撰写&#xff0c;他们共同创立了创新颠覆实验室&#xff08;Creative Destruction Lab&#xff0c;简称CDL&#xff09;&#xff0c;实验室的研究领域主要集中在人工智能和决策领域。他们通过《A…

java 词法分析练习

import parser.Parser;import java.util.ArrayList; import java.util.Arrays; import java.util.List;public class Main {public static void main(String[] args) {// 关键词List<String> keyList new ArrayList<>(Arrays.asList("int","String…