l S (shared locks) 共享鎖:允許擁有鎖的事務讀一行數據
l X (exclusive locks) 排他鎖:允許有用鎖的事務更新或刪除一行數據
如果一個事務T1在行r擁有一個S共享鎖,從不同的事務T2請求鎖定行r,處理如下:
l 事務T2能立即獲得行r的S共享鎖,因此,T1和T2都在行r上持有S共享鎖
l 事務T2不能獲得行r的X排它鎖
如果一個事務T1在行r持有x排它鎖,其他事務T2無法獲得任何類型的鎖。
Innodb支持多粒度鎖定,這種鎖定允許事務在行級上的鎖和表級上的鎖同時存在。為了支持在不同粒度上進行加鎖操作,innodb支持一種額外的鎖方式,稱為意向鎖(intention locks)。
Innodb意向鎖為表級別的鎖,設計的主要目的主要是為了在下一個事務中揭示下一行將被請求的鎖類型。
InnoDB中有2中類型的意向鎖:
? Intention shared (IS): Transaction T intends to set S locks on individual rows in table t.
事務T想對表t的某些行設置共享鎖
? Intention exclusive (IX): Transaction T intends to set X locks on those rows.
事務T想對表t的某些行設置排它鎖
例如:SELECT ... LOCK IN SHARE MODE 設置了一個IS鎖
SELECT ... FOR UPDATE 設置一個IX鎖
意向鎖協議如下:
? 一個事務在可以獲得表t的某些行的S共享鎖,必須先獲取表t的IS意向共享鎖
? 一個事務在可以會的表t的某些行的X排它鎖,必須先獲取表t的IX意向排它鎖
Innodb鎖兼容性矩陣
意向鎖不會堵塞除了全表操作(例:LOCK TABLES ...WRITE)以外的任何請求,其意向鎖的主要目的是顯示某些操作鎖定了某行,或者將要鎖定某行。
意向鎖的存在價值在于在定位到特定的行所持有的鎖之前,提供一種更粗粒度的鎖,可以大大節約引擎對于鎖的定位和處理的性能,因為在存儲引擎內部,鎖是由一塊獨立的數據結構維護的,鎖的數量直接決定了內存的消耗和并發性能。例如,事務A對表t的某些行修改(DML通常會產生X鎖),需要對t加上意向排它鎖,在A事務完成之前,B事務來一個全表操作(alter table等),此時直接在表級別的意向排它鎖就能告訴B需要等待(因為t上有意向鎖),而不需要再去行級別判斷
意向鎖實際上可以理解為一種“暗示”未來需要什么樣行級鎖:
IS表示未來可能需要在這個表的某些記錄上加共享鎖
IX表示未來可能需要在這個表的某些記錄上加排他鎖。
意向鎖是表級別的,IS和IX鎖之間相互并不沖突,但與表級S/X鎖沖突。
在對記錄加S鎖或者X鎖時,必須保證其在相同的表上有對應的意向鎖或者鎖強度更高的表級鎖
Innodb的行鎖的類型:
? Record lock: 鎖定一個索引記錄
? Gap lock: 鎖定一個范圍,不包含記錄本身
? Next-key lock: Gap lock+ Record lock,鎖定一個范圍,并且鎖定記錄本身
Record Locks總是鎖住索引記錄,即使表沒有定義索引,Innodb會創建一個隱試的聚集索引來鎖定。
Next-key Locks 默認Innodb使用RR的隔離級別。在這種情況下,InnoDB使用next-key鎖機制來查詢數據和索引掃描,防止幻象問題
Next-key locking結合了index-row鎖和Gap鎖。當搜索和查詢索引操作時,InnoDB使用行鎖的方式,在相應的索引記錄上設置共享或者排他鎖。因此,行級別的鎖實際上是索引記錄鎖。而Next-Key鎖是索引記錄鎖加范圍鎖。如果一個會話在索引記錄R上加了一個共享或者排他鎖,其他會話不能立即插入一個新的索引記錄在索引記錄R之前的間隙中。
假設一個索引的值有10, 11, 13, 和20,那么該索引可能被Next-Key Locking的區間為:
最后一個間隔范圍,Next-Key 實際上鎖定的范圍是僅僅是最大索引值后面的范圍。
當操作的索引是唯一的情況下,Innodb會對Next-key Locking進行優化,將其降級為Record Lock,只鎖住索引本身,而不是鎖定范圍。
如下:
|
Session A |
Session B |
|
Session A>drop table t; |
|
|
|
Session A>begin; |
|
#session A提交上面的事務 Session A>commit; |
|
上面的實驗中,表t有1,2,5三個值。在session A中對a=5進行鎖定讀X鎖定,但因為字段a是主鍵(唯一索引),因此此時鎖定的僅是5這個索引記錄,而不是(2,5)]這個范圍,這樣在Session B中能順利的插入a=4(4在(2,5]之間)而不會阻塞。上述正式因為Next-Key Lock對唯一索引的記錄降級為record lock的原因,從而可以提高應用的并發性。
當查詢的列是非唯一的索引時,情況如下:
|
Session A |
Session B |
|
Session A>drop table t; |
|
|
注意:右邊的Session B看到15被堵塞,而20沒有被堵塞;所以,推測此處Gap Lock的范圍是【15,20)和(20,25)。這與官當上的http://dev.mysql.com/doc/refman/5.7/en/innodb-record-level-locks.html舉的例子的 可能的間隔范圍剛好閉開區間是反的 |
#18在[15,20)之間,被堵塞 |
Gap Locks 當使用唯一索引查詢唯一的行時,不需要Gap locks.
前面next-key的例子表明gap可能覆蓋一個單獨的索引值,多個索引值,或可能是空的。
例如:下面的語句只需要在id為100的行上使用一個index-record lock,而不會影響其他會話插入數據:
SELECT * FROM child WHERE id = 100 for update;
如果ID不是索引或者不是一個uniq index,該語句則使用Gap Locking.
插入意向Gap鎖(insert intention gap lock)在Insert操作之前被設置。這種鎖的目的是:當多個事務插入數據到相同的索引間隙,只要他們插入的索引間隙內的位置不同,則不需要相互等待。假如有索引值4和7,某個事務視圖在4和7的間隙間插入5和6,在插入的行會分配插入意向Gap鎖,但因為5和6的行并不沖突,所以不會堵塞對方。
注意:不同的事務在一個間隙(Gap)上可以持有互斥的鎖。例如:當事務B在某個Gap上擁有一個排他Gap鎖,事務A在相同的Gap上可以持有共享Gap鎖。此處允許鎖沖突共存的原因是:當從一個索引上purge一個記錄,其他事務對此記錄加的Gap鎖會被被合并。
Gap鎖在Innodb中是”完全禁止的”。這意味著它們只能防止其他事務在一個Gap中的插入操作。因此,排他Gap鎖和共享Gap鎖具有同樣的效果。
Disabling Gap Locking
Gap鎖可以被完全關閉方法是設置事務隔離級別修改為RC,或者開啟innodb_locks_unsafe_for_binlog系統變量(此選項5.6和5.7已經被棄用)。關閉Gap的情況下,除了在外鍵一致性檢查和逐漸沖突檢查的時候,gap鎖均不生效。
RC隔離級別和開啟innodb_locks_unsafe_for_binlog參數也會帶來其他影響,比如:在mysql分析where條件之后,未匹配行的記錄鎖就會被釋放(違反了2PL:Two Parsing Lock原則)例如:在update中,innodb執行"半一致性"讀,這樣,最新的提交版本被告知mysql,然后由mysql決定行是否匹配執行Update操作的where條件。
參考鏈接:
http://dev.mysql.com/doc/refman/5.7/en/innodb-lock-modes.html
http://dev.mysql.com/doc/refman/5.7/en/innodb-record-level-locks.html
http://hedengcheng.com/?p=771#_Toc374698322
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。