Transactional超時時間timeout控制

項目使用的是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秒。

總結:功夫不負有心人,只要一步步深入調查,什麼問題終究會得出答案。


原文地址:http://blog.csdn.net/qing_gee/article/details/41897321

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章