InnoDB數(shù)據(jù)庫死鎖問題處理
場景描述
在update表的時候出現(xiàn)DeadlockLoserDataAccessException異常 (Deadlock found when trying to get lock; try restarting transaction...)。
問題分析
這個異常并不會影響用戶使用,因為數(shù)據(jù)庫遇到死鎖會自動回滾并重試。用戶的感覺就是操作稍有卡頓。但是監(jiān)控老是報異常,所以需要解決一下。
解決方法
在應(yīng)用程序中update的地方使用try-catch。
我自己封裝了一個函數(shù),如下。
/**
* 2016-03-15
* linxuan
* handle deadlock while update table
*/
private void updateWithDeadLock(TestMapper mapper, Test record) throws InterruptedException {
boolean oops;
int retries = 5;
do{
oops = false;
try{
mapper.updateByPrimaryKeySelective(record);
}
catch (DeadlockLoserDataAccessException dlEx){
oops = true;
Thread.sleep((long) (Math.random() * 500));
}
finally {
}
} while(oops == true && retries-- >0);
}
我用的是mybatis,所以只需將mapper傳進函數(shù),如果不用mybatis,需要自己創(chuàng)建并關(guān)閉數(shù)據(jù)庫連接。
延伸:數(shù)據(jù)庫死鎖
數(shù)據(jù)庫死鎖是事務(wù)性數(shù)據(jù)庫 (如SQL Server, MySql等)經(jīng)常遇到的問題。除非數(shù)據(jù)庫死鎖問題頻繁出現(xiàn)導(dǎo)致用戶無法操作,一般情況下數(shù)據(jù)庫死鎖問題不嚴(yán)重。在應(yīng)用程序中進行try-catch就可以。那么數(shù)據(jù)死鎖是如何產(chǎn)生的呢?
InnoDB實現(xiàn)的是行鎖 (row level lock),分為共享鎖 (S) 和 互斥鎖 (X)。
共享鎖用于事務(wù)read一行。
互斥鎖用于事務(wù)update或delete一行。
當(dāng)客戶A持有共享鎖S,并請求互斥鎖X;同時客戶B持有互斥鎖X,并請求共享鎖S。以上情況,會發(fā)生數(shù)據(jù)庫死鎖。如果還不夠清楚,請看下面的例子。
數(shù)據(jù)庫死鎖例子
首先,客戶A創(chuàng)建一個表T,并向T中插入一條數(shù)據(jù),客戶A開始一個select事務(wù),所以拿著共享鎖S。
mysql> CREATE TABLE t (i INT) ENGINE = InnoDB; Query OK, 0 rows affected (1.07 sec) mysql> INSERT INTO t (i) VALUES(1); Query OK, 1 row affected (0.09 sec) mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE; +------+ | i | +------+ | 1 | +------+
然后,客戶B開始一個新事務(wù),新事務(wù)是delete表T中的唯一一條數(shù)據(jù)。
mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) mysql> DELETE FROM t WHERE i = 1;
刪除操作需要互斥鎖 (X),但是互斥鎖X和共享鎖S是不能相容的。所以刪除事務(wù)被放到鎖請求隊列中,客戶B阻塞。
最后,客戶A也想刪除表T中的那條數(shù)據(jù):
mysql> DELETE FROM t WHERE i = 1; ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
死鎖產(chǎn)生了!因為客戶A需要鎖X來刪除行,而客戶B拿著鎖X并正在等待客戶A釋放鎖S。看看客戶A,B的狀態(tài):
客戶A: 拿著鎖S,等待著客戶B釋放鎖X。
客戶B: 拿著鎖X,等待著客戶A釋放鎖S。
發(fā)生死鎖后,InnoDB會為對一個客戶產(chǎn)生錯誤信息并釋放鎖。返回給客戶的信息:
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction
所以,另一個客戶可以正常執(zhí)行任務(wù)。死鎖結(jié)束。
- mysql 數(shù)據(jù)庫死鎖原因及解決辦法
- Mysql 數(shù)據(jù)庫死鎖過程分析(select for update)
- 簡單說明Oracle數(shù)據(jù)庫中對死鎖的查詢及解決方法
- Mybatis update數(shù)據(jù)庫死鎖之獲取數(shù)據(jù)庫連接池等待
- MySQL數(shù)據(jù)庫的一次死鎖實例分析
- 講解Oracle數(shù)據(jù)庫中結(jié)束死鎖進程的一般方法
- 記一次公司倉庫數(shù)據(jù)庫服務(wù)器死鎖過程及解決辦法
- 查詢Sqlserver數(shù)據(jù)庫死鎖的一個存儲過程分享
- MySQL數(shù)據(jù)庫之Purge死鎖問題解析
- 5分鐘快速了解數(shù)據(jù)庫死鎖產(chǎn)生的場景和解決方法
相關(guān)文章
Mysql 數(shù)字類型轉(zhuǎn)換函數(shù)
Mysql 數(shù)字類型轉(zhuǎn)換函數(shù),有此需要的朋友可以參考下用法。2009-08-08
MYSQL5 masterslave數(shù)據(jù)同步配置方法
因線路或安全需要我們不得不考慮mysql的備份,特把mysql數(shù)據(jù)備份的方法整理下。2008-09-09

