概述
每個MySQL DBA和開發可能都會在工作過程中遇到死鎖問題,死鎖是并發系統中比較常見的問題,同樣也會出現在數據庫系統的并發讀寫請求場景中。當兩個及以上的事務,雙方都在等待對方釋放已經持有的鎖或因為加鎖順序不一致造成循環等待鎖資源,就會出現"死鎖"。
由于加鎖順序不一致造成的死鎖在RC(READ-COMMIT)隔離級別下較為常見,本文分享一個RR(REPEATABLE-READ)隔離級別下由于GAP鎖導致的死鎖案例。
案例
得知有死鎖發生時,首先查看數據庫隔離級別為默認的RR(REPEATABLE-READ)模式:
然后再查看innodb存儲引擎日志可以看到最近一次死鎖的相關信息:
從日志中我們可以看出死鎖發生在表T_ORDERBILL_TASK上而且是兩條相同類型的針對表T_ORDERBILL_TASK插入的insert語句!檢查T_ORDERBILL_TASK表結構如下:
可見ORG_CODE上有二級索引。
1. TRANSACTION也就是第一個事務的信息中:
WAITING FOR THIS LOCK TO BE GRANTED,表示的是這個事務在等待的鎖信息;
index ORG_CODE of table `T_BSE_QUERY_SCHEME`.`T_ORDERBILL_TASK`表示等的是表T_ORDERBILL_TASK上ORG_CODE索引上面的鎖;
lock_mode X locks gap before rec insert intention waiting Record lock 表示這個語句要加一個插入意向鎖但是還在等待狀態,Record lock說明這是一個記錄鎖。
2. TRANSACTION 也就是第二個事務中:
(2) HOLDS THE LOCK(S)中lock_mode X locks gap before rec 表示了持有GAP鎖
(2) WAITING FOR THIS LOCK TO BE GRANTED中lock_mode X locks gap before rec insert intention waiting同(1)TRANSACTION等待加插入意向鎖
結合業務開發提供的該模塊兒的業務邏輯和發生死鎖時間上下文業務日志可以整理出事務1和事務2的執行順序為:
或者
可以看出在插入一條數據前先執行當前讀鎖住該條數據,弱不存在則插入該條數據,否則執行update。
由于索引是順序存儲的,查出110026介于110019和110036之間:
由此可知:
當session 1執行select ... for update當前讀,由于ORG_CODE = 110026的數據不存在,因此會加上gap鎖(110019,110036)。
Session 2執行select ... for update當前讀,同樣也會加上gap鎖(110019,110036),由于gap鎖不互斥,所以該語句也可成功執行。
但是到第三步時無論是session 1先插入還是session 2先插入都會等待對方的gap鎖,第四步時后插入的也會被對方的gap鎖阻塞。兩個session進入互相等待狀態形成死鎖,最后死鎖檢測將session2回滾。
結論
其實GAP鎖,就是RR隔離級別相對于RC隔離級別不會出現幻讀的關鍵。
在RR隔離級別下,條件列上為非唯一索引時,當前讀通過條件列未定位到滿足條件的記錄時會加GAP鎖,保證后續的insert不能插入相同值的數據,以防止出現幻讀。需要注意的是GAP鎖并不互斥但是和插入意向鎖互斥。相同語句的情況下RR模式由于會加GAP鎖可能鎖住更多的數據,雖然防止了幻讀,但是會影響一定的并發。在配置RC和RR隔離級別的時候一定要根據業務場景進行選擇。
更多精彩干貨分享
點擊下方名片關注
IT那活兒
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/129763.html
摘要:問題描述近期項目需要從虛擬機環境遷移到容器環境,其中有一個項目在遷移到容器環境之后的兩天之內出現了次死鎖的問題,部分關鍵日志如下日志還是挺明顯的,線程獲得了鎖,等待獲取而正好相反,從而導致死鎖問題分析以上的錯誤 問題描述 近期項目需要從虛擬機環境遷移到容器環境,其中有一個項目在遷移到容器環境之后的兩天之內出現了2次死鎖(deadlock)的問題,部分關鍵日志如下: Found one ...
摘要:的情況下,必然就會死鎖,對吧,接下來怎么用驗證呢切到號線程查看線程棧及棧對象。死鎖原因分析死鎖原因分析要想追究死鎖的原因,只能仔細推敲線程棧線程棧對象。在幾個痙攣過程中進入了另外一個線程池的方法中,希望能得到該池中的鎖對象。一:背景1. 講故事這個月初,星球里的一位朋友找到我,說他的程序出現了死鎖,懷疑是自己的某些寫法導致mongodb出現了如此尷尬的情況,截圖如下:說實話,看過這么多dum...
摘要:此時我想到了福爾摩斯說過的一句話當你排除掉各種不可能出現的情況之后,剩下的情況無論多么難以置信,都是真相。福爾摩斯冷靜下來想一想,這個線程,有可能靜悄悄地退出了嗎,沒留下半點異常日志從理論上來說,不可能。配置建議最后,附上一份配置建議。 1、事發 我們有個視頻處理程序,基于 SpringBoot,會啟動幾個線程來跑。要退出程序時,會發送一個信號給程序,每個線程收到信號后會平滑退出,等全...
摘要:記一次優惠券最優使用算法先說一下業務背景。公司做的一個投資的,投資金額可以用優惠券抵扣。但是無法獲取具體使用了哪張優惠券簡單就是很難獲得優惠券的窮舉法數據太多,不可控。但是這種面額的優惠券出現幾率幾乎沒有請教期待有大神給出更好的算法 記一次優惠券最優使用算法 先說一下業務背景。公司做的一個投資的APP,投資金額可以用優惠券抵扣。紅包面額(100,50,30,10) 優惠券使用規則: ...
閱讀 1346·2023-01-11 13:20
閱讀 1684·2023-01-11 13:20
閱讀 1132·2023-01-11 13:20
閱讀 1858·2023-01-11 13:20
閱讀 4100·2023-01-11 13:20
閱讀 2704·2023-01-11 13:20
閱讀 1385·2023-01-11 13:20
閱讀 3597·2023-01-11 13:20