Transactional超時時間控制與mysql事務超時時間
阿新 • • 發佈:2019-01-27
專案使用的是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; } }
先想到的是不是mybatis的原因,因為mybatis在xml定義update語句時也提供了超時時間設定,見如下說明,
timeout單位是毫秒 這個設定驅動程式等待資料庫返回請求結果,並丟擲異常時間的最大等待值。預設不設定(驅動自行處理)。OK,我對update語句加上超時2秒處理
<update id="updateTotalmoneyForPerTransfermoneyOut" parameterType="hashmap" timeout="2000">
mysql> show variables like 'innodb_lock_wait_timeout'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | innodb_lock_wait_timeout | 50 | +--------------------------+-------+ 1 row in set
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秒。
總結:功夫不負有心人,只要一步步深入調查,什麼問題終究會得出答案。