1. 程式人生 > >Mysql鎖詳解(行鎖、表鎖、意向鎖、Gap鎖、插入意向鎖)

Mysql鎖詳解(行鎖、表鎖、意向鎖、Gap鎖、插入意向鎖)

鎖:對 “某種範圍” 的資料上 “某種鎖”

1.“某種範圍”:行、表 2.“某種鎖”

2.1 共享鎖Shared Locks(S鎖)

1、相容性:加了S鎖的記錄,允許其他事務再加S鎖,不允許其他事務再加X鎖

2、加鎖方式:select…lock in share mode

2.2 排他鎖Exclusive Locks(X鎖)

1、相容性:加了X鎖的記錄,不允許其他事務再加S鎖或者X鎖

2、加鎖方式:select…for update

2.3 表鎖:意向鎖 Intention Locks,意向鎖相互相容

1、表明“某個事務正在某些行持有了鎖、或該事務準備去持有鎖”

2、意向鎖的存在是為了協調行鎖和表鎖的關係,支援多粒度(表鎖與行鎖)的鎖並存,。

3、例子:事務A修改user表的記錄r,會給記錄r上一把行級的排他鎖(X),同時會給user表上一把意向排他鎖(IX),這時事務B要給user表上一個表級的排他鎖就會被阻塞。意向鎖通過這種方式實現了行鎖和表鎖共存且滿足事務隔離性的要求。
InnoDB 的意向鎖有什麼作用? - 網易雲的回答 - 知乎

4、1)意向共享鎖(IS鎖):事務在請求S鎖前,要先獲得IS鎖
2)意向排他鎖(IX鎖):事務在請求X鎖前,要先獲得IX鎖

q1:為什麼意向鎖是表級鎖呢?
當我們需要加一個排他鎖時,需要根據意向鎖去判斷表中有沒有資料行被鎖定(行鎖);

(1)如果意向鎖是行鎖,則需要遍歷每一行資料去確認;

(2)如果意向鎖是表鎖,則只需要判斷一次即可知道有沒資料行被鎖定,提升效能。

q2:意向鎖怎麼支援表鎖和行鎖並存?
(1)首先明確並存的概念是指資料庫同時支援表、行鎖,而不是任何情況都支援一個表中同時有一個事務A持有行鎖、又有一個事務B持有表鎖,因為表一旦被上了一個表級的寫鎖,肯定不能再上一個行級的鎖。
(2)如果事務A對某一行上鎖,其他事務就不可能修改這一行。這與“事務B鎖住整個表就能修改表中的任意一行”形成了衝突。所以,沒有意向鎖的時候,讓行鎖與表鎖共存,就會帶來很多問題。於是有了意向鎖的出現,如q1的答案中,資料庫不需要在檢查每一行資料是否有鎖,而是直接判斷一次意向鎖是否存在即可,能提升很多效能。

5、下圖表示意向鎖和共享鎖、排他鎖的相容關係。
意思是 當事務A對某個資料範圍(行或表)上了“某鎖”後,另一個事務B是否能在這個資料範圍上“某鎖”。

在這裡插入圖片描述

意向鎖相互相容,因為IX、IS只是表明申請更低層次級別元素(比如 page、記錄)的X、S操作。

因為上了表級S鎖後,不允許其他事務再加X鎖,所以表級S鎖和X、IX鎖不相容

上了表級X鎖後,會修改資料,所以表級X鎖和 IS、IX、S、X(即使是行排他鎖,因為表級鎖定的行肯定包括行級速訂的行,所以表級X和IX、行級X)不相容。

注意:上了行級X鎖後,行級X鎖不會因為有別的事務上了IX而堵塞,一個mysql是允許多個行級X鎖同時存在的,只要他們不是針對相同的資料行。

2.4 行鎖:記錄鎖(Record Locks)

(1)記錄鎖, 僅僅鎖住索引記錄的一行,在單條索引記錄上加鎖。
(2)record lock鎖住的永遠是索引,而非記錄本身,即使該表上沒有任何索引,那麼innodb會在後臺建立一個隱藏的聚集主鍵索引,那麼鎖住的就是這個隱藏的聚集主鍵索引。
所以說當一條sql沒有走任何索引時,那麼將會在每一條聚合索引後面加X鎖,這個類似於表鎖,但原理上和表鎖應該是完全不同的。

2.5 行鎖:間隙鎖(Gap Locks)

(1)區間鎖, 僅僅鎖住一個索引區間(開區間,不包括雙端端點)。
(2)在索引記錄之間的間隙中加鎖,或者是在某一條索引記錄之前或者之後加鎖,並不包括該索引記錄本身。

比如在 1、2、3中,間隙鎖的可能值有 (∞, 1),(1, 2),(2, ∞),
(3)間隙鎖可用於防止幻讀,保證索引間的不會被插入資料

2.6 *行鎖:臨鍵鎖(Next-Key Locks)

(1)record lock + gap lock, 左開右閉區間。
(2)預設情況下,innodb使用next-key locks來鎖定記錄。select … for update
(3)但當查詢的索引含有唯一屬性的時候,Next-Key Lock 會進行優化,將其降級為Record Lock,即僅鎖住索引本身,不是範圍。
(4)Next-Key Lock在不同的場景中會退化:

在這裡插入圖片描述

2.7 行鎖:插入意向鎖(Insert Intention Locks)

(1)插入意向鎖是一種Gap鎖,不是意向鎖,在insert操作時產生。
(2)在多事務同時寫入不同資料至同一索引間隙的時候,並不需要等待其他事務完成,不會發生鎖等待。
(3)假設有一個記錄索引包含鍵值4和7,不同的事務分別插入5和6,每個事務都會產生一個加在4-7之間的插入意向鎖,獲取在插入行上的排它鎖,但是不會被互相鎖住,因為資料行並不衝突。

(4)插入意向鎖不會阻止任何鎖,對於插入的記錄會持有一個記錄鎖。
例如test表存在若干資料的資料,先開始一個事務A,插入一條n=5的資料;(圖中步驟1)
此時如果開始一個事務B,執行查詢 select * from test where n > 4 for update,事務B會申請Gap鎖(4, ∞),申請成功後,被事務A的x鎖阻塞,直到x鎖被釋放。(圖中步驟2)
可以看到圖中步驟3的資訊,在等待事務釋放X鎖

2.8 鎖的相容性

在這裡插入圖片描述

2.9 表鎖:自增鎖(AUTO-INC Locks)

AUTO-INC鎖是一種特殊的表級鎖,發生涉及AUTO_INCREMENT列的事務性插入操作時產生。

3.鎖的選擇

1.如果更新條件沒有走索引,例如執行”update test set name=“hello” where name=“world”;” ,此時會進行全表掃描,掃表的時候,要阻止其他任何的更新操作,所以上升為表鎖。

2.如果更新條件為索引欄位,但是並非唯一索引(包括主鍵索引),例如執行“update test set name=“hello” where code=9;” 那麼此時更新會使用Next-Key Lock。使用Next-Key Lock的原因:

首先要保證在符合條件的記錄上加上排他鎖,會鎖定當前非唯一索引和對應的主鍵索引的值;

還要保證鎖定的區間不能插入新的資料。

如果更新條件為唯一索引,則使用Record Lock(記錄鎖)。

幫助知識

1.檢視事務、鎖的sql
select from information_schema.innodb_locks;
select from information_schema.innodb_lock_waits;
select * from information_schema.innodb_trx;