程序死鎖的問題,很難調試,看進程堆棧,看各個線程與鎖的狀況,對照代碼進行排查。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";
不放心的話,能夠用上面兩個語句查詢確認。調試
如上圖,用SecureCRT開啓兩個窗口:
(1)窗口A,先啓動事務,並插入記錄;
(2)窗口B,再啓動事務,也插入記錄;
(3)窗口A,修改插入的記錄;
(4)窗口B,也修改插入的記錄;
奇怪的現象發生了,若是併發事務的update語句:
(1)更新條件是cell,就會發生異常;
(2)更新條件是id,就一切正常;
按道理,插入不衝突的記錄,而後修改這條記錄,行鎖不該該衝突呀?惟一索引,主鍵索引怎麼會有差別呢?是否有關?是死鎖,仍是其餘緣由?
你們幫忙分析分析,到底問題在哪裏呢?
有可能,要用到這裏的知識:
《MySQL併發控制與鎖+調試MySQL死鎖d方法》
架構師之路-分享技術思路
相關推薦:
《寫一個cache,要掌握哪些技術點》
《6條shell小技巧 | 1分鐘系列》
歡迎討論,下一篇,和你們同步結果。畫外音:思考以後,印象更加深入。