熟悉或者瞭解數據庫的朋友都知道鎖的概念,這裏不做過多的解析!鎖的種類有很多,不同數據庫的鎖管理方式也不同。這裏主要談下MySQL innodb引擎下的死鎖。
死鎖通俗的來講就是2個事務相互請求對方持有的鎖,這樣就會造成2個事務相互等待對方釋放的鎖資源,於是這就是死鎖。
事務A | 事務B |
begin; | |
select * from t where a = 1 for update; | begin; |
select * from t where a = 2 for update; | |
select * from t where a = 2 for update; | |
select * from t where a = 1 for update; #ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction |
首先INNODB引擎不會回滾大多數的異常,但死鎖除外。再發現死鎖後,Innodb會立即回滾其中一個事務(這裏回滾依據,會設計到權重問題)。例子中事務B被回滾!這是最常見的一種死鎖例子。
MySQL還有另外一種死鎖情況:當前事務持有待插入記錄的下一個記錄的X鎖(排他鎖),但此時等待的隊列中存在一個S鎖的請求,則可能會發生死鎖。首先創建一個測試用的表,並插入數據:
create table test( a int primary key) engine=innodb;
insert into test values (1),(2),(4),(5);
時間 | 事務A | 事務B |
1 | begin; | |
2 | begin; | |
3 | select * from test where a = 4 for update; | |
4 | select * from test where a<=4 lock in share mode; #等待 | |
5 | insert into test values (3) ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction | |
6 | #事務獲得鎖,正常運行 |
事務A中已經對記錄4持有了X鎖,但會話A插入記錄3的時候會導致死鎖發生。這個問題產生是由於事務B中請求記錄4的S鎖而發生等待,但之前請求鎖對於主鍵記錄1、2都已經成功,若再時間5能插入記錄,那麼事務B在獲取記錄4持有的S鎖後,還需要向後獲得記錄3的記錄,這顯得不合理。於是INNODB引擎在這裏主動選擇死鎖。