一次mysql死鎖的發現
這篇文章主要介紹了筆者在業務擴展的時候,設計欠妥,導致的死鎖,以及解決方案
本題難點在於下面這幾部分:
INSERT併發執行:在DDB的RC事務下面的併發插入
INSERT、DELETE併發執行:
INTENTION LOCK產生的原因與前提:
INSERT併發執行
對於INSERT操作來說,若發生唯一約束衝突,則需要對衝突的唯一索引加上S Next-key Lock。從這裏會發現,即使是RC事務隔離級別,也同樣會存在Next-Key Lock鎖,從而阻塞併發。
沒有唯一主鍵的併發操作
表結構如下:
單次insert事務,並不提交,模擬併發提交情況
另起一事務,提交多次insert
可以發現事務非常順利的被提交了,commit之後也發現數據很順利的提交上來了
唯一主鍵的併發操作
表結構如下:
單次insert事務,不提交,模擬併發提交情況
另一個事務提交時,發現表鎖
鎖日誌如下
INSERT、DELETE併發執行:
以無唯一主鍵表爲例
表結構如下:
單次delete事務,不提交,模擬併發提交情況(非主鍵刪除)
另一個事務執行insert的時候,發現表鎖,(無論userId是否在刪除隊列裏)
日誌如下:
單次delete事務,不提交(主鍵刪除)
另一個事務執行insert的時候,沒有發現表鎖,順利提交
INTENTION LOCK產生的原因與前提:
INSERT INTENTION LOCK,翻譯爲插入意向鎖,其實準確來說應該是INSERT INTENTION GAP LOCK。這個鎖類型在老版本的InnoDB中並不存在,後來是爲了優化插入性能而設計的。官方文檔中的說明如下:
Prior to inserting the row, a type of gap lock called an insert intention gap lock is set. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap.
在RC事務隔離級別下,由於插入大部分是不需要等待的,所以這把鎖大部分時候也是不存在的。只有當發生鎖等待時,即插入的這條記錄下一條記錄next_rec有鎖,並且帶有GAP屬性,則這時需要對next_rec再加一個插入意向鎖。由於插入意向鎖和S/X Lock不兼容,因此需要等待。
在RC事務隔離級別下,雖然大多數插入操作是併發的,不會發生鎖等待。然而,由於唯一約束的存在,這時就需要加上插入意向鎖。而這也是上次死鎖案例問題產生的原因。