乙個MySQL死鎖問題的反思

2021-09-22 19:25:03 字數 2125 閱讀 7720

很早之前我寫過幾篇關於mysql死鎖的分析,比如

但是感覺不過癮,而且分析的都是一些特定的場景,好像還缺少一些舉一反三的感覺,所以今天就補上這一波。

mysql裡的鎖相容列表大體是這樣的關係,如果第一次看會有些暈,感覺抓不住重點,其實有一點小技巧。

首先innodb實現了兩種類似的行鎖,即s(共享鎖)和x(排他鎖),而innodb層面的表級意向鎖有is(意向共享鎖)和ix9意向排他鎖),意向鎖之間是互相相容的,這句話很重要,按照這個思路裡面一半的內容就明確了。而另外一部分則是s和x的相容性。帶著s鎖和x鎖的組合都是互相排斥,只有一類場景例外,那就是都是s鎖,是相容的。所以這個圖按照這個思路幾乎不用記就能基本理解了。

看起來s鎖的組合是很柔和的,從這種場景來看保持相容,那麼出死鎖的概率應該很低吧,其實在rr,rc隔離級別下我們可以逐步擴充套件然後舉一反三。

如果s鎖的組合在兩個會話中是互相相容,那麼接下來的x鎖的組合就是互相排斥的。

那麼在兩個會話併發的場景下,死鎖的步驟如下:

mysql> create table dt1 (id int unique

query ok, 0 rows affected (0.03 sec)

會話1:

begin;

select *from dt1 lock in share mode; --顯式共享鎖

會話2:

begin;

select *from dt1 lock in share mode; --顯式共享鎖

會話1:

insert into dt1 values(1); --阻塞

會話2:

insert into dt1 values(2); --觸發死鎖

所以上面的語句特點很明顯,插入的資料分別是1和2,看起來互補衝突也不行。

我們進度稍快一些,我們可能很少看到直接宣告share mode的方式,但是有很多時候由其他的場景會觸發,其中的乙個主要原因就在於對於duplicate資料的檢查會開啟s鎖。這是比較特別的一點,需要注意。

按照這一點來擴充套件,很容易就可以擴充套件到3個會話中。

會話1只是負責插入一條資料,會話2,3也緊接著插入一條記錄(會話2,3自動提交),但是因為唯一性索引的檢查,會導致會話2和會話3都開啟了s鎖,因為相容,所以暫時還沒影響。如果會話1正常提交,會話2,3的檢查會生效,導致資料插入不了,違反唯一性約束,但是我們反其道而行,就可以用乙個rollback來釋放鎖,緊接著會話2和會話3都會獲得s鎖成功,緊接著獲得x鎖,細節演算法就不說了。這個時候互相阻塞,導致會話3產生死鎖,會話2的資料插入依然會成功。

會話1:

begin;

insert into dt1 values(1);

會話2:

insert into dt1 values(1);

會話3:

insert into dt1 values(1);

會話1:

rollback;

看起來很精巧的小測試,但是裡面蘊含這大道理,比如按照這個思路,如果後面的兩個語句都是delete,也會觸發死鎖。有的時候我們可以正面來圖例,或者通過死鎖日誌來推理。給我的乙個啟發是太極。

放在鎖的角度來理解就會好很多。

用一張不太形象的圖表示就是,左邊的部分是insert操作在會話1中,右邊的是在會話2和會話3中,都持有s鎖,然後會因為同樣的原因事務回滾後,他們的s鎖會公升級為x鎖導致死鎖發生。

按照這個思路,我們可以繼續擴充套件出幾個場景。比如delete的方式。

按照這樣的思路,可以構建出很多的死鎖場景來。

乙個死鎖問題

表結構 create table test id bigint 20 unsigned not null auto increment comment 自增id a varchar 100 not null default comment 唯一健 b bigint 20 unsigned not n...

乙個執行緒死鎖問題的分析

客戶報過來乙個問題,伺服器執行一周左右就會停止響應,有時候甚至兩天就不響應了,併發使用者量並不大,重啟服務後又工作正常。每當遇到這種問題時就有點兒棘手。一是這種問題的復現條件不好確定,另一方面,即使確定了條件,對於多執行緒的服務程式,也不好除錯。我遇到過的這種問題,大部分是靠讀 分析出來乙個可能的原...

遇到乙個Mysql死鎖問題,記錄下

對一張表做批量編輯,表的基本介面如下 t test bigint id,int status,varchar clientid,更新語句是 update t test set status 2 where clientid 當批量操作時,批量提交多次update語句,每次語句執行是需要做以下操作 1...