當前位置:編程學習大全網 - 熱門推薦 - mysql中insert會加鎖嗎

mysql中insert會加鎖嗎

加鎖情況與死鎖原因分析

為方便大家復現,完整表結構和數據如下:

CREATE TABLE `t3` (

`c1` int(11) NOT NULL AUTO_INCREMENT,

`c2` int(11) DEFAULT NULL,

PRIMARY KEY (`c1`),

UNIQUE KEY `c2` (`c2`)

) ENGINE=InnoDB

insert into t3 values(1,1),(15,15),(20,20);

在 session1 執行 commit 的瞬間,我們會看到 session2、session3 的其中壹個報死鎖。這個死鎖是這樣產生的:

1.?session1 執行 delete ?會在唯壹索引 c2 的 c2 = 15 這壹記錄上加 X lock(也就是在MySQL 內部觀測到的:X Lock but not gap);

2.?session2 和 session3 在執行 insert 的時候,由於唯壹約束檢測發生唯壹沖突,會加 S Next-Key Lock,即對 (1,15] 這個區間加鎖包括間隙,並且被 seesion1 的 X Lock 阻塞,進入等待;

3.?session1 在執行 commit 後,會釋放 X Lock,session2 和 session3 都獲得 S Next-Key Lock;

4.?session2 和 session3 繼續執行插入操作,這個時候 INSERT INTENTION LOCK(插入意向鎖)出現了,並且由於插入意向鎖會被 gap 鎖阻塞,所以 session2 和 session3 互相等待,造成死鎖。

死鎖日誌如下:

請點擊輸入圖片描述

INSERT INTENTION LOCK

在之前的死鎖分析第四點,如果不分析插入意向鎖,也是會造成死鎖的,因為插入最終還是要對記錄加 X Lock 的,session2 和 session3 還是會互相阻塞互相等待。

但是插入意向鎖是客觀存在的,我們可以在官方手冊中查到,不可忽略:

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.

插入意向鎖其實是壹種特殊的 gap lock,但是它不會阻塞其他鎖。假設存在值為 4 和 7 的索引記錄,嘗試插入值 5 和 6 的兩個事務在獲取插入行上的排它鎖之前使用插入意向鎖鎖定間隙,即在(4,7)上加 gap lock,但是這兩個事務不會互相沖突等待。

當插入壹條記錄時,會去檢查當前插入位置的下壹條記錄上是否存在鎖對象,如果下壹條記錄上存在鎖對象,就需要判斷該鎖對象是否鎖住了 gap。如果 gap 被鎖住了,則插入意向鎖與之沖突,進入等待狀態(插入意向鎖之間並不互斥)。總結壹下這把鎖的屬性:

1. 它不會阻塞其他任何鎖;

2. 它本身僅會被 gap lock 阻塞。

在學習 MySQL 過程中,壹般只有在它被阻塞的時候才能觀察到,所以這也是它常常被忽略的原因吧...

GAP LOCK

在此例中,另外壹個重要的點就是 gap lock,通常情況下我們說到 gap lock 都只會聯想到 REPEATABLE-READ 隔離級別利用其解決幻讀。但實際上在 READ-COMMITTED 隔離級別,也會存在 gap lock ,只發生在:唯壹約束檢查到有唯壹沖突的時候,會加 S Next-key Lock,即對記錄以及與和上壹條記錄之間的間隙加***享鎖。

通過下面這個例子就能驗證:

請點擊輸入圖片描述

這裏 session1 插入數據遇到唯壹沖突,雖然報錯,但是對 (15,20] 加的 S Next-Key Lock 並不會馬上釋放,所以 session2 被阻塞。另外壹種情況就是本文開始的例子,當 session2 插入遇到唯壹沖突但是因為被 X Lock 阻塞,並不會立刻報錯 “Duplicate key”,但是依然要等待獲取 S Next-Key Lock 。

有個困惑很久的疑問:出現唯壹沖突需要加 S Next-Key Lock 是事實,但是加鎖的意義是什麽?還是說是通過 S Next-Key Lock 來實現的唯壹約束檢查,但是這樣意味著在插入沒有遇到唯壹沖突的時候,這個鎖會立刻釋放,這不符合二階段鎖原則。這點希望能與大家壹起討論得到好的解釋。

如果是在 REPEATABLE-READ,除以上所說的唯壹約束沖突外,gap lock 的存在是這樣的:

普通索引(非唯壹索引)的S/X Lock,都帶 gap 屬性,會鎖住記錄以及前1條記錄到後1條記錄的左閉右開區間,比如有[4,6,8]記錄,delete 6,則會鎖住[4,8)整個區間。

對於 gap lock,相信 DBA 們的心情是壹樣壹樣的,所以我的建議是:

1. 在絕大部分的業務場景下,都可以把 MySQL 的隔離界別設置為 READ-COMMITTED;

2. 在業務方便控制字段值唯壹的情況下,盡量減少表中唯壹索引的數量。

鎖沖突矩陣

前面我們說的 GAP LOCK 其實是鎖的屬性,另外我們知道 InnoDB 常規鎖模式有:S 和 X,即***享鎖和排他鎖。鎖模式和鎖屬性是可以隨意組合的,組合之後的沖突矩陣如下,這對我們分析死鎖很有幫助:

請點擊輸入圖片描述

  • 上一篇:2014元旦股市放假幾天
  • 下一篇:美麗鄉村的作文
  • copyright 2024編程學習大全網