MySQL InnoDB支持三種行鎖定方式:sql
- 行鎖(Record Lock):鎖直接加在索引記錄上面。
- 間隙鎖(Gap Lock):鎖加在不存在的空閒空間,能夠是兩個索引記錄之間,也多是第一個索引記錄以前或最後一個索引以後的空間。
- Next-Key Lock:行鎖與間隙鎖組合起來用就叫作Next-Key Lock。
默認狀況下,InnoDB工做在可重複讀隔離級別下,而且以Next-Key Lock的方式對數據行進行加鎖,這樣能夠有效防止幻讀的發生。Next-Key Lock是行鎖與間隙鎖的組合,這樣,當InnoDB掃描索引記錄的時候,會首先對選中的索引記錄加上行鎖(Record Lock),再對索引記錄兩邊的間隙(向左掃描掃到第一個比給定參數小的值, 向右掃描掃描到第一個比給定參數大的值, 而後以此爲界,構建一個區間)加上間隙鎖(Gap Lock)。若是一個間隙被事務T1加了鎖,其它事務是不能在這個間隙插入記錄的。session
舉個例子:
表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。高併發