mysql 間隙鎖


在學習mysql鎖過程中有些想法記錄與分享

環境:mysql5.6  innodb存儲引擎,默認隔離級別repeatable-read,可重復讀。innodb_locks_unsafe_for_binlog, 參數默認值是OFF,也就是啟用間隙鎖, 他是一個bool值, 當值為true時表示disable間隙鎖

知識:與oracle不同的是,mysql加鎖是對索引加鎖

在進行刪除或者修改操作時,如果過濾條件列是非唯一索引,為了保證當前讀的數據一致性,mysql通過間隙鎖對數據之間區域進行鎖定。(實際上是通過鎖定索引達到效果)

這種鎖叫間隙鎖,這種鎖定會造成許多誤殺,很多並不沖突的數據會因為間隙鎖而無法插入。

 

舉例:

准備測試數據

create table test (id int,name varchar(10));
alter table test add primary key PK_ID (id);
alter table test add index INX_Name (name);
insert into test values (1,'a1');
insert into test values (2,'a1');
insert into test values (3,'a1');
insert into test values (4,'a3');
insert into test values (5,'a4');
insert into test values (11,'a6');
insert into test values (21,'a10');
insert into test values (22,'a13');
insert into test values (23,'a14');
insert into test values (24,'a15');

session one;

 

 

刪除name='a3',因為間隙鎖的緣故,會對 (24,a15)和(4,a3)之間加鎖,(4,a3)和(5,a4)之間加鎖。

很明顯,如果我們想插入a2到name字段中,必然會因為間隙鎖,而處於等待狀態。

 

測試:session two

 

insert into test(id,name) values (30,'a2'); 插入等待,並且鎖等待超時。

 

同樣a3,a4之間插入數據也會處於等待超時。

 

這時很容易想到一個問題,如果間隙鎖是在兩組數據中間加鎖,那么如果我插入a3兩邊的數據,a15或者a4,是否會出現鎖等待呢。

繼續做測試:

繼續插入:insert into test(id,name) values(20,'a15');

                 insert into test(id,name) values(26,'a15');

可以看到插入ID 20很快成功,插入ID 26 出現鎖等待。

同樣是a15,因為ID不同,結果不一樣,是什么原因呢。

我們來看插入后的一個查詢,很容易就理解了:

這個查詢是按照name列的索引做的順序排序,我們可以看到 (20,a15)已經插入成功。

我們已經知道在(24,a15)和(4,a3)之間存在間隙鎖,如果數據(26,a15)需要插入進去,那么必然會排在24 a15之后

形成:

20   a15

24   a15

26   a15

4     a3

而這樣的數據必然會被間隙鎖阻塞,因此導致鎖等待。

所以我們在上面明確間隙鎖的時候,需要書寫一組數據(主鍵列,輔助索引列),而不是單單只寫一列。

 

最后得出結論:間隙鎖鎖定了輔助索引兩個葉子節點之間的內容,會造成鎖定多余區域的數據。

先delete再insert的操作時常會導致死鎖情況的出現。

應用程序sql中,在做刪除或者更新操作中,對於過濾條件盡量選擇主鍵列或者唯一索引列

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM