问题
在做项目的时候遇到了一个问题:
我的这个代码就光看的话,延时8秒,怎么都应该超时3秒了啊,应该回滚吧,但是运行日志是这样的
问题代码
错误日志
他自动就提交了,不是我们想要的超时回滚效果
查询了很多资料,依旧没有解决,最后无意之间增加一个数据库操作,他就自动回滚了
解决方案
在延时操作前后都增加数据库操作,一定要是前后都有数据库操作
当超时之后,数据库操作1就会回滚,这就是我们想要的效果
超时回滚了
原理解析
Spring事务超时检查机制
Spring事务超时检查不是实时的监控,而是在特定时刻触发检查:
1.检查点设置:Spring在事务开始时记录开始时间戳
2.触发检查时机:只有在执行JDBC操作(数据库读写)时才会检查是否超时
3.超时计算:当前时间 - 事务开始时间 > 配置的超时时间
在整个方法里面记录整个方法的执行时间
像我这个问题里面,事务开启后,先执行数据库操作1,这个时候并没有提交事务,然后再执行延时操作,延时操作执行完之后,这个时候整个方法其实已经超时了,但是我们说了spring检查是否超时只会在执行数据库操作的时候才会检查,所以如果延时之后没有数据库操作的话,数据库会默认不检查超时,直接自动提交
事务超时检查的精确机制
1.事务开始:
方法调用时,事务启动
记录开始时间戳 T₀
2.第一次数据库操作:
执行前检查:当前时间 T₁ - T₀ < 超时阈值(3秒)
因为刚开始执行,所以 T₁ - T₀ 很小,通过检查
执行操作,但不提交事务(事务在整个方法结束前都不会提交)
3.执行延时操作:
睡眠8秒,超过了配置的3秒超时阈值
但这不是数据库操作,不会触发超时检查
系统此时不知道已经超时
4.如果有后续数据库操作:
执行前会检查:当前时间 T₂ - T₀ > 超时阈值(已经超过8秒)
检测到超时,抛出异常,回滚事务
5.如果没有后续数据库操作:
没有触发点来检查超时
方法执行完毕,Spring认为事务执行正常
系统提交事务,尽管实际上已经超时
常见误解澄清
有几个关于事务开始的常见误解:
1.❌ 误解:事务在第一次数据库操作时才开始
✓ 事实:事务在方法调用时就已开始,与方法内是否立即执行数据库操作无关
2.❌ 误解:每个数据库操作都是独立的小事务
✓ 事实:整个方法是一个事务单元,所有数据库操作共享同一个事务
3.❌ 误解:耗时操作会中断事务
✓ 事实:无论方法内执行什么操作,事务都持续到方法结束
希望能帮到你