Transactional超时时间控制

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: Transactional超时时间控制

项目使用的是spring+mybatis+mysql,今天,我需要把处理一个业务就是,当用户出金失败时,事务能够回滚,同时减少用户的等待时间,因为我发现当处理失败时,用户需要等上1分钟以上的时间,这是不合理的。那么经过一系列的调查发现:spring的事务超时(使用Java注解方式)和mysql InnoDB事务超时是相互关联的。

在一个需要进行事务回滚的方法上加入@Transactional的事务注解,timeout超时时间设置为2秒,也就是说发生事务回滚后,2秒钟后对用户响应。

@Transactional(timeout=2)
public int updateForzenMoney(MoneyTransfer moneyTransfer, int uid) {
    // 如果是出金请求,则预扣除冻结资金
    if (moneyTransfer.getType().intValue() == 1) {
        moneyTransferService.updateTotalmoneyForPerTransfermoney(uid, moneyTransfer.getAmount());
        // 将请求插入money_transfer表中
        moneyTransferService.addMoneyTransfer(moneyTransfer);
        return 1;
    } else {
        moneyTransferService.addMoneyTransfer(moneyTransfer);
        return 2;
    }
}

通过mysql控制台的模拟操作(强迫发生事务回滚),发现updateForzenMoney方法前后执行时间远远大于2秒的时间,为什么呢?

先想到的是不是mybatis的原因,因为mybatis在xml定义update语句时也提供了超时时间设置,见如下说明,
timeout单位是毫秒
这个设置驱动程序等待数据库返回请求结果,并抛出异常时间的最大等待值。默认不设置(驱动自行处理)。
OK,我对update语句加上超时2秒处理

继续执行,发现执行时间依然远远大于2+2+2,接近50毫秒,这期间又测试了很多种组合方式,然后我看到 mysql的配置文件(my.cnf)中,innodb_lock_wait_timeout=50 ,而我所使用的表刚好是innodb类型。

mysql> show variables like 'innodb_lock_wait_timeout';
Variable_name Value
innodb_lock_wait_timeout 50

1 row in set

ok,找到了他,那么到底是不是呢,修改一下
mysql> set
innodb_lock_wait_timeout = 10;
Query OK, 0 rows affected

mysql> show variables like 'innodb_lock_wait_timeout';
Variable_name Value
innodb_lock_wait_timeout 10

1 row in set
继续执行,发现执行时间接近了10秒左右,然后再将10秒设置为20秒,ok,测试出来的超时时间大概是20秒,说明这个思路是正确的,但是为什么spring的事务超时时间没有起到作用呢,继续调查

把mysql的时间再设置短一点,然后再次把spring的事务超时设置为5秒,把mybatis的超时去掉
mysql> set innodb_lock_wait_timeout = 1
;
Query OK, 0 rows affected

mysql> show variables like 'innodb_lock_wait_timeout';
Variable_name Value
innodb_lock_wait_timeout 1

1 row in set

@Transactional(timeout=5)
public int updateForzenMoney(MoneyTransfer moneyTransfer, int uid) {

然后再执行,看日志时间
DEBUG 2014-12-12 16:53:49,784 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Preparing: UPDATE money_us
DEBUG 2014-12-12 16:53:49,785 org.apache.ibatis.logging.jdbc.BaseJdbcLogger: ==> Parameters:
DEBUG 2014-12-12 16:54:00,795
事务回滚的时间差不多刚好是两个statement的事务执行时间5+5=10秒的时间 。

结论:spring的事务超时时间和mysql的事务超时时间是相互影响的!我最后确认的方案是,修改mysql的innodb超时时间为20秒,然后去掉Java方法上的超时时间
@Transactional
public int updateForzenMoney(MoneyTransfer moneyTransfer, int uid) {
再次,测试,事务的回滚时间大概是20秒。

总结:功夫不负有心人,只要一步步深入调查,什么问题终究会得出答案。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
存储 NoSQL Java
使用Redisson RLock锁防止定时任务短周期重复执行
在开发定时任务时,如果任务执行周期较短,可能会导致任务在前一次执行尚未完成时就再次触发,从而产生重复执行的问题。为了解决这个问题,我们可以借助Redisson的RLock锁机制,确保任务只有在前一次执行完成后才能再次执行。本文将介绍如何使用Redisson RLock锁来避免定时任务的重复执行。
504 0
使用Redisson RLock锁防止定时任务短周期重复执行
|
SQL 运维 监控
高并发接口超时时间过长,导致服务雪崩
高频访问接口超时时间过长,导致服务雪崩
530 0
高并发接口超时时间过长,导致服务雪崩
|
消息中间件 NoSQL Java
Springboot 指定重发的次数和延迟时间,定时异步执行 重发任务
Springboot 指定重发的次数和延迟时间,定时异步执行 重发任务
897 0
Springboot 指定重发的次数和延迟时间,定时异步执行 重发任务
|
6月前
|
XML Java 数据库
java如何设置事务超时时间
【2月更文挑战第16天】
358 3
|
11月前
|
设计模式 负载均衡 Java
Feign如何设置超时时间,不同情况还真不一样,别设置错了
大家好,我是三友~~ 今天来聊一聊前段时间看到的一个面试题,也是在实际项目中需要考虑的一个问题,Feign的超时时间如何设置? Feign的超时时间设置方式并不固定,它取决于Feign在项目中是如何使用的,不同的使用方式,超时时间设置方式也不大相同,甚至还可能有坑。
Feign如何设置超时时间,不同情况还真不一样,别设置错了
|
11月前
aop计时,超时输出日志
aop计时,超时输出日志
67 0
|
SQL 监控 JavaScript
接口突然超时10宗罪。。。
接口突然超时10宗罪。。。
|
SQL XML Java
事务超时
本文概览:介绍了超时有关的概念:@Transaction的timeout、mybatis的timeout、mysql的innodb_lock_wait_timeout。
事务超时
|
网络协议
10w定时任务,如何高效触发超时
很多时候,业务有定时任务或者定时超时的需求,当任务量很大时,可能需要维护大量的timer,或者进行低效的扫描。
810 0