一次詭異的數據庫「死鎖」,問題究竟在哪裏?

程序死鎖的問題,很難調試,看進程堆棧,看各個線程與鎖的狀況,對照代碼進行排查。shell

數據庫死鎖的問題,更難,看不了數據庫堆棧,也看不了數據庫線程與鎖,更難以對照代碼排查。數據庫

前段時間,和一個朋友討論了一個「疑似」數據庫死鎖的問題,最後進行試驗與排查,找到了問題所在。session

場景以下:

一次詭異的數據庫「死鎖」,問題究竟在哪裏?
同一個表,高併發事務,事務內先插入一條記錄,再更新這條記錄:
(1)若是更新的是惟一索引,有異常;
(2)若是更新的是自增主鍵,就沒有異常;
畫外音:先不要被「dead lock」描述所迷惑,是死鎖問題,阻塞問題,仍是其餘異常,還另說。架構

一次詭異的數據庫「死鎖」,問題究竟在哪裏?
並且,據朋友所述,還可以復現:
(1)開啓事務;
(2)插入記錄;
(3)sleep 5秒;
(4)修改被插入的記錄;
在併發時穩定復現。併發

根據朋友的描述,在線下開了多個MySQL客戶端進行了併發模式測試,結果還挺出乎意料的。ide

第一步:數據準備

create table t (
id int(20) primary key AUTO_INCREMENT,
cell varchar(20) unique
)engine=innodb;

新建表:
(1)存儲引擎是innodb,MySQL版本是5.6;
(2)id字段,自增主鍵;
(3)cell字段,惟一索引;高併發

start transaction;
insert into t(cell) values(11111111111);
insert into t(cell) values(22222222222);
insert into t(cell) values(33333333333);
commit;

插入一些測試數據。

第二步:session參數設置
事務的隔離級別,事務的自動提交等參數設置不當,都會對實驗的結果產生影響,詢問了朋友,事務的隔離級別是RR(repeatable read)。測試

set session autocommit=0;
set session transaction isolation level repeatable read;

每個session啓動後:
(1)關閉自動提交;
(2)把事務隔離級別設爲RR;
一次詭異的數據庫「死鎖」,問題究竟在哪裏?線程

show session variables like "autocommit";
show session variables like "tx_isolation";

不放心的話,能夠用上面兩個語句查詢確認。調試

第三步:多個終端session模擬併發事務

一次詭異的數據庫「死鎖」,問題究竟在哪裏?
如上圖,用SecureCRT開啓兩個窗口:
(1)窗口A,先啓動事務,並插入記錄;
(2)窗口B,再啓動事務,也插入記錄;
(3)窗口A,修改插入的記錄;
(4)窗口B,也修改插入的記錄;

奇怪的現象發生了,若是併發事務的update語句:
(1)更新條件是cell,就會發生異常;
(2)更新條件是id,就一切正常;

按道理,插入不衝突的記錄,而後修改這條記錄,行鎖不該該衝突呀?惟一索引,主鍵索引怎麼會有差別呢?是否有關?是死鎖,仍是其餘緣由?

你們幫忙分析分析,到底問題在哪裏呢?

有可能,要用到這裏的知識:
《MySQL併發控制與鎖+調試MySQL死鎖d方法》
一次詭異的數據庫「死鎖」,問題究竟在哪裏?
架構師之路-分享技術思路
相關推薦:
《寫一個cache,要掌握哪些技術點》
《6條shell小技巧 | 1分鐘系列》

歡迎討論,下一篇,和你們同步結果。畫外音:思考以後,印象更加深入。

相關文章
相關標籤/搜索