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

相关推荐

  1. spring事务异常不如何解决

    2024-04-27 05:40:01       40 阅读
  2. Spring事务规则,是否只读,超时时间,事务失效

    2024-04-27 05:40:01       82 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-27 05:40:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-27 05:40:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-27 05:40:01       87 阅读
  4. Python语言-面向对象

    2024-04-27 05:40:01       96 阅读

热门阅读

  1. CentOS7.9环境下安装mysql-8.0.32详解

    2024-04-27 05:40:01       31 阅读
  2. 四级英语之词类的确定

    2024-04-27 05:40:01       34 阅读
  3. C语言——通讯录实现

    2024-04-27 05:40:01       30 阅读
  4. linux下建立cpp文件,然后通过cmake编译。

    2024-04-27 05:40:01       32 阅读
  5. 【数据结构与算法】力扣 459. 重复的子字符串

    2024-04-27 05:40:01       35 阅读
  6. NFT学习资料整理

    2024-04-27 05:40:01       24 阅读
  7. 丑数 II

    2024-04-27 05:40:01       46 阅读