热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Spring事务超时探讨

先抛出一个问题,如下,Spring事务的默认超时时间是多少?先来看如下代码,方法上加上了事务注解,并设置事务超

先抛出一个问题,如下,Spring事务的默认超时时间是多少?

图片

先来看如下代码,方法上加上了事务注解,并设置事务超时时间为2s。两者的区别是一个是在插入之前Sleep了3秒,一个是在插入之后Sleep了3秒。测试时发现,前者会抛事务超时异常,而后者则正常插入了,这是为什么呢?

图片

图片

如上,insertStuTimeOut1方法抛出了事务超时异常。我们可以观察它异常栈信息,来分析它是如何一步步走到超时异常的。


  1. 我们知道,Mybatis执行SQL是将SQL封装成一个Statement去执行。如下这边根据方法名称知道它是在准备Statement,而在这里它调用了SpringManagedTransaction的getTimeout方法,这里面会检测事务是否超时了。(Mybatis在3.4.0版本及以上才会去检测Spring事务是否超时,https://github.com/mybatis/spring/issues/115)

图片

图片

图片


  1. 现在来看下为什么insertStuTimeOut1方法超时了,而insertStuTimeOut2方法没有超时?原因刚刚也提到了,Mybatis在执行SQL前会去检测事务是否超时?关键是两者Sleep的时间,insertStuTimeOut2方法中SQL执行时还没有Sleep,所以自然不会超时了。如下图所示,Mybatis是先生成Statement,在生成Statement时就会去检测是否超时。然后才会去执行SQL。

图片


  1. 步骤1中有一个关键的变量deadline,顾名思义,它是截止日期,如果当前似乎超过了deadline,说明超时了需要回滚。那么deadline是在哪边设置的呢?它是在创建事务的时候设置的。

图片

图片


  1. 现在来回答文章开头的问题,Spring默认的事务超时时间是多少?这是@Transactional注解中对事务超时的默认值设置,默认是-1。

图片

在步骤3) 中创建事务给事务设置超时时间时,会调用determineTimeout方法来计算事务超时时间,如果是默认的则返回defaultTimeout,也就是-1。

图片

那么在这一步就不会初始化deadline变量,也就是说deadline变量为null。

图片

而在这一步getTimeout中会去调用holder.getTimeout方法判断deadline是否为null,如果为null,则不会去检测事务是否超时。也就是说,如果不手动设置@Transactional的timeout属性,Mybatis是不会去检测Spring事务是否超时的。

图片

public boolean hasTimeout() { return (this.deadline != null);
}

思考分析,Mybatis这样检测Spring事务是否超时有没有什么问题?它在SQL执行前去执行SQL超时判断?如果SQL执行很长时间,则Mybatis不会认为它是超时的而去回滚它。这本质上是一种同步检测机制。而Hystrix启动单独的线程去检测超时,线程启动的时间刚好就是任务超时的时间,这是一种异步检测机制。


推荐阅读
author-avatar
一个醒不来的梦zyc
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有