Spring事务超时到底是怎么回事?

环境:Spring5.3.23
Spring事务超时是指一个事务在执行中最长的允许时间 。如果事务在超时时间内未能完成,则会自动回滚 。超时时间可以通过设置来控制,以确保事务在规定的时间内完成或回滚,避免数据一致性问题 。
在工作中你有配置事务的超时时间吗?如何进行配置事务超时时间?
1. 配置事务超时时间注解方式:
// 这里单位是s@Transactional(timeout = 2)public void save() {}编程方式1:
@Resourceprivate PlatformTransactionManager tm ;DefaultTransactionDefinition definition = new DefaultTransactionDefinition();definition.setTimeout(2) ;编程方式2:
@Resourceprivate PlatformTransactionManager tm ;public void update() {TransactionTemplate template = new TransactionTemplate(tm) ;template.setTimeout(2) ;template.execute(new TransactionCallback<Object>() {@Overridepublic Object doInTransaction(TransactionStatus status) {// ...return null ;}}) ;}以上3种方式读可以进行事务超时的设置 , 什么情况下才能算是事务超时呢?
2. 准备环境准备一张2000w数据的表

Spring事务超时到底是怎么回事?

文章插图
图片
表字段信息如下:
Spring事务超时到底是怎么回事?

文章插图
图片
此表除主键外没有任何的索引 。
Spring事务超时到底是怎么回事?

文章插图
图片
3. 模拟事务超时
  • 测试1
统计查询表的数据量 , 将该操作放到一个事务中 , 同时设置事务的超时时间 。
// 将超时时间设置为20s@Transactional(timeout = 20)public void query() {long start = System.currentTimeMillis() ;jdbcTemplate.execute("select count(*) from p_user") ;System.out.println("耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;}执行结果:
耗时:3198毫秒接下来将超时时间改成3s
执行结果如下:
13:56:01.425 [mAIn] WARNc.zaxxer.hikari.pool.ProxyConnection - HikariPool-1 - Connection com.MySQL.cj.jdbc.ConnectionImpl@504ecd marked as broken because of SQLSTATE(null), ErrorCode(0)com.mysql.cj.jdbc.exceptions.MySQLTimeoutException: Statement cancelled due to timeout or client requestat com.mysql.cj.jdbc.exceptions.SQLExceptionsMApping.translateException(SQLExceptionsMapping.JAVA:113)at com.mysql.cj.jdbc.StatementImpl.checkCancelTimeout(StatementImpl.java:2167)从异常信息看到抛出了超时异常 。这里的超时是sql执行的超时,是由我们的驱动程序抛出的异常 。
  • 测试2
模拟其它非数据库操作耗时,而这个是在执行数据库操作之前
@Transactional(timeout = 2)public void query() {long start = System.currentTimeMillis() ;try {TimeUnit.SECONDS.sleep(3) ;} catch (InterruptedException e) {e.printStackTrace();}// 执行非常简单的操作jdbcTemplate.execute("select 1") ;System.out.println("耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;}执行结果:
14:08:44.000 [main] DEBUG o.s.jdbc.core.JdbcTemplate - Executing SQL statement [select 1]Exception in thread "main" org.springframework.transaction.TransactionTimedOutException: Transaction timed out: deadline was Wed Oct 11 14:08:42 CST 2023at org.springframework.transaction.support.ResourceHolderSupport.checkTransactionTimeout(ResourceHolderSupport.java:155)抛出了超时异常,而这个异常是由Spring框架抛出的 。
  • 测试3
模拟其它非数据库操作耗时 , 而这个是在执行数据库操作之后,适当调整上面的代码顺序
@Transactional(timeout = 2)public void query() {long start = System.currentTimeMillis() ;jdbcTemplate.execute("select 1") ;try {TimeUnit.SECONDS.sleep(3) ;} catch (InterruptedException e) {e.printStackTrace();}System.out.println("耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;}执行结果:
耗时:3015毫秒程序正常运行
  • 测试4
在测试3的基础上,最后再次执行数据库相关的操作
@Transactional(timeout = 2)public void query() {long start = System.currentTimeMillis() ;jdbcTemplate.execute("select 1") ;try {TimeUnit.SECONDS.sleep(3) ;} catch (InterruptedException e) {e.printStackTrace();}System.out.println("耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;// 再次执行数据库相关操作jdbcTemplate.execute("select 1") ;}


推荐阅读