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

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

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

相关文章

IEC 62680新规上线,慧能泰设备端PD协议芯片带你勇闯欧盟

2022年12月7日&#xff0c;欧盟发布了Directive (EU) 2022/2380&#xff0c;强化了通用充电器的规定&#xff0c;并计划于2024年12月28日起&#xff0c;在所有欧盟国家强制执行该指令。此修订主要针对新生产的手机、平板、相机、耳机、游戏机、音箱、电子书、键盘、鼠标、导航仪…

使用knuth Durstenfeld Shuffle置乱关键区域

示意图 使用knuth Durstenfeld Shuffle置乱关键区域。比较典型的就是当我们对图像进行小波变换后&#xff0c;能量主要集中在左上角。 将图像进行排列&#xff0c;将关键区域置于整个序列的末尾&#xff0c;从末尾开始逐个交换&#xff0c;完成置换。 为了演示方便&#xff0c…

第 3 篇 : Netty离线消息处理(可跳过)

说明 仅是个人的不成熟想法, 未深入研究验证 1. 修改 NettyServerHandler类 package com.hahashou.netty.server.config;import com.alibaba.fastjson.JSON; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHan…

CRM客户管理系统盘点2024:16款顶级系统PK赛,寻找最佳利器

客户关系管理系统&#xff08;CRM&#xff09;在企业数字化转型的过程中扮演着至关重要的角色。选择一个高效、功能丰富的CRM客户管理系统&#xff0c;对于确保企业未来健康、稳定的发展至关重要。当前市场上存在着众多的CRM客户管理系统件&#xff0c;每个软件都有其独特的功能…

C#开发的全套成熟的LIS系统源码JavaScript+SQLserver 2012区域云LIS系统源码

C#开发的全套成熟的LIS系统源码JavaScriptSQLserver 2012区域云LIS系统源码 医院云LIS系统是一套成熟的实验室信息管理系统&#xff0c;目前已在多家三级级医院应用&#xff0c;并不断更新。云LIS系统是为病人为中心、以业务处理为基础、以提高检验科室管理水平和工作效率为目标…

攻防世界 easyphp

本题主要利用的知识点是php绕过 一、PHP代码分析 首先先看一下代码 我们需要利用get方式上传3个参数a,b,c&#xff0c;这3个分别需要满足不同的条件: a&#xff1a;设置a值&#xff1b;值大于6000000&#xff1b;长度不超过3&#xff1b; b&#xff1a;设置b值&#xff1b;MD…

MT8788智能模块简介_MTK联发科安卓核心板方案厂商

MT8788安卓核心板是一款具备超高性能和低功耗的4G全网通安卓智能模块。该模块采用联发科AIOT芯片平台&#xff0c;供货周期长。 MT8788核心板搭载了12nm制程的四个Cortex-A73处理器核心和四个Cortex-A53处理器核心&#xff0c;最高主频可达2.0GHz。板载内存容量可选为4GB64GB(也…

Linux2.6内核进程调度队列

目录 运行队列runqueue 活跃队列&过期队列 queue[140]&优先级&队列数组下标 bitmap[5]&O(1)调度算法 nr_active active指针和expired指针 O(1)调度算法之调度过程 本篇是Linux进程概念篇的最后一篇&#xff0c;Linux2.6内核是一个具体的/可行的/实际的存…

【计算机系统基础读书笔记】1.1.2 冯诺依曼机基本结构

1.1.2 冯诺依曼机基本结构 冯诺依曼机基本结构如图所示&#xff1a; 模型机中主要包括&#xff1a; 主存储器&#xff1a;用来存放指令和数据&#xff0c;简称主存或内存&#xff1b; 算数逻辑部件&#xff08;Arithmetic Logic Unit&#xff0c;简称ALU&#xff09;&#x…

SignalR中的重连机制和心跳监测机制详解

一. 重连机制 声明&#xff1a;   本节仅介绍重连机制和心跳监测机制&#xff0c;基于Core 3.1框架&#xff0c;至于SignalR其它的一些基本使用&#xff0c;包括引入、Hub、配置等常规操作&#xff0c;在本节中不介绍&#xff0c;后续写Core下的SignalR 说明   默认是没有重…

Log4j日志框架多种日志级别

Log4j日志框架定义了多种日志级别&#xff0c;这些级别按照优先级从高到低排列如下&#xff1a; OFF&#xff1a;这是最高等级的日志级别&#xff0c;用于关闭所有日志记录。FATAL&#xff1a;指出每个严重的错误事件将会导致应用程序的退出。ERROR&#xff1a;表明发生错误事…

C++之STL-list+模拟实现

目录 一、list的介绍和基本使用的方法 1.1 list的介绍 1.2 list的基本使用方法 1.2.1 构造方法 1.2.2 迭代器 1.2.3 容量相关的接口 1.2.4 增删查改的相关接口 1.3 关于list迭代器失效的问题 二、模拟实现list 2.1 节点类 2.2 迭代器类 2.3 主类list类 2.3.1 成员变…