zoukankan      html  css  js  c++  java
  • Transactional超时时间控制与mysql事务超时时间

    项目使用的是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秒处理
    <update id="updateTotalmoneyForPerTransfermoneyOut" parameterType="hashmap" timeout="2000">

    继续执行,发现执行时间依然远远大于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秒。

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


  • 相关阅读:
    P4049 [JSOI2007]合金
    CF1073C Vasya and Robot
    输出100以内奇数,偶数,质数,合数的脚本
    取/etc/password文件最后一个单词的最后一个字符
    window下进程退出后自动重启
    如何让DOS命令在新窗口打开
    dos命令关闭所有dos窗口
    使用jps查看JVM进程信息
    windows .bat批处理实现进程监控确保程序运行
    经典博客4(六尺帐篷)
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13317601.html
Copyright © 2011-2022 走看看