Mysql innodb 間隙鎖 (轉)


MySQL InnoDB支持三種行鎖定方式:

  • 行鎖(Record Lock):鎖直接加在索引記錄上面。
  • 間隙鎖(Gap Lock):鎖加在不存在的空閑空間,可以是兩個索引記錄之間,也可能是第一個索引記錄之前或最后一個索引之后的空間。
  • Next-Key Lock:行鎖與間隙鎖組合起來用就叫做Next-Key Lock。

默認情況下,InnoDB工作在可重復讀隔離級別下,並且以Next-Key Lock的方式對數據行進行加鎖,這樣可以有效防止幻讀的發生。Next-Key Lock是行鎖與間隙鎖的組合,這樣,當InnoDB掃描索引記錄的時候,會首先對選中的索引記錄加上行鎖(Record Lock),再對索引記錄兩邊的間隙(向左掃描掃到第一個比給定參數小的值, 向右掃描掃描到第一個比給定參數大的值, 然后以此為界,構建一個區間)加上間隙鎖(Gap Lock)如果一個間隙被事務T1加了鎖,其它事務是不能在這個間隙插入記錄的


舉個例子:
表task_queue
Id           taskId
1              2
3              9
10            20
40            41

開啟一個會話: session 1
sql> set autocommit=0;
   ##
取消自動提交

sql> delete from task_queue where taskId = 20;
sql> insert into task_queue values(20, 20);

在開啟一個會話: session 2
sql> set autocommit=0;
   ##
取消自動提交

sql> delete from task_queue where taskId = 25;
sql> insert into task_queue values(30, 25);

在沒有並發,或是極少並發的情況下, 這樣會可能會正常執行,在Mysql中, 事務最終都是穿行執行, 但是在高並發的情況下, 執行的順序就極有可能發生改變, 變成下面這個樣子:
sql> delete from task_queue where taskId = 20;
sql> delete from task_queue where taskId = 25;
sql> insert into task_queue values(20, 20);
sql> insert into task_queue values(30, 25);

這 個時候最后一條語句:insert into task_queue values(30, 25); 執行時就會爆出死鎖錯誤。因為刪除taskId = 20這條記錄的時候,20 --  41 都被鎖住了, 他們都取得了這一個數據段的共享鎖, 所以在獲取這個數據段的排它鎖時出現死鎖。

間隙鎖在InnoDB的唯一作用就是防止其它事務的插入操作,以此來達到防止幻讀的發生,所以間隙鎖不分什么共享鎖與排它鎖。另外,在上面的例子中,我們選擇的是一個普通(非唯一)索引字段來測試的,這不是隨便選的,因為如果InnoDB掃描的是一個主鍵、或是一個唯一索引的話,那InnoDB只會采用行鎖方式來加鎖,而不會使用Next-Key Lock的方式,也就是說不會對索引之間的間隙加鎖,仔細想想的話,這個並不難理解,大家也可以自己測試一下。

 

要禁止間隙鎖的話,可以把隔離級別降為讀已提交,或者開啟參數innodb_locks_unsafe_for_binlog


免責聲明!

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



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