[譯]Innodb中的鎖

原文地址InnoDB Locking

本章節(jié)描述了InnoDB中使用的鎖.

  • 共享鎖和排它鎖
  • 意向鎖
  • 記錄鎖
  • 間隙鎖
  • Next-Key鎖
  • 插入意向鎖
  • AUTO-INC 鎖

共享鎖和排它鎖

InnoDB實現(xiàn)了標準的行級別鎖虽惭,包括兩種類型:共享鎖和排它鎖

  • 獲取到共享鎖(S)的事務可以讀取這一行橡类。
  • 獲取到排它鎖(X)的事務可以更改或刪除這一行。

如果事務T1拿到了第r行的S鎖芽唇,那么另外一個事務T2對第r行的鎖請求將會被如下處理:

  • 如果T2請求獲取共享鎖顾画,那么可以立即成功。結(jié)果是T1和T2都拿到了第r行的共享鎖。
  • 如果T2請求獲取排他鎖亲雪,那么將不會立即成功勇凭。

如果T1拿到了第r行的排它鎖,那么T2無論請求哪個類型的鎖义辕,都不會立即成功虾标。T2必須等待T1釋放第r行的鎖,才有可能拿到鎖灌砖。

意向鎖

InnoDB支持多個粒度的鎖璧函,它允許行級別鎖和表鎖同時存在。為了實現(xiàn)這一點基显,InnoDB使用了額外的鎖蘸吓,叫做意向鎖。意向鎖是表級別的鎖撩幽,當事務使用某種類型的意向鎖時库继,說明事務接下來要請求表中的某一行的同類型鎖。InnoDB中使用了兩種類型的意向鎖:

  • 意向共享鎖(IS): 事務接下來要對表中某一行加共享鎖窜醉。
  • 意向排它所(IX): 事務接下來要對表中某些行加排它鎖宪萄。

舉例來說,SELECT ... LOCK IN SHARE MODE加了意向共享鎖榨惰,SELECT ... FOR UPDATE加了意向排它鎖拜英。
意向鎖工作機制如下:

  • 事務在獲取表t的第r行的共享鎖之前,必須先獲取t的IS鎖琅催,或者更強的鎖居凶。
  • 事務在獲取表t的第r行的排它鎖之前,必須先獲取t的IX鎖藤抡。
X IX S IS
X 沖突 沖突 沖突 沖突
IX 沖突 兼容 沖突 兼容
S 沖突 沖突 兼容 兼容
IS 沖突 兼容 兼容 兼容

這些規(guī)則可以總結(jié)為一個二維的鎖兼容性矩陣侠碧,如下:

X IX S IS
X 沖突 沖突 沖突 沖突
IX 沖突 兼容 沖突 兼容
S 沖突 沖突 兼容 兼容
IS 沖突 兼容 兼容 兼容

如果事務請求的鎖與當前已存在的鎖兼容,那么事務將成功獲取鎖缠黍,否則將會等待舆床,直到這個已存在的沖突的鎖被釋放為止。如果一個與當前存在的鎖沖突的鎖請求成功了嫁佳,那么將會導致死鎖錯誤挨队。
因此,意向鎖只會阻塞要求獲取整個表的那種請求蒿往。IX和IS存在的主要目的是說明當前有某個事務鎖住了一行數(shù)據(jù)盛垦,或者將要鎖住一行數(shù)據(jù)。
使用SHOW ENGINE INNODB STATUS命令以及InnoDB monitor可以查看意向鎖瓤漏,如下:

TABLE LOCK table `test`.`t` trx id 10080 lock mode IX

記錄鎖

記錄鎖是加在索引記錄上的鎖腾夯。舉例來說颊埃,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;阻止了其他事務插入、修改或者刪除cl的值為10的這一行記錄蝶俱。

記錄鎖總是鎖在索引上班利,即使這個表在定義時沒有定義索引。這種情況下榨呆,InnoDB會創(chuàng)建一個隱藏的組合索引罗标,并使用這個索引來給記錄加鎖。(查看聚合索引和二級索引)

使用SHOW ENGINE INNODB STATUS命令以及InnoDB monitor可以查看記錄鎖积蜻,如下:

RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t` 
trx id 10078 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000a; asc     ;;
 1: len 6; hex 00000000274f; asc     'O;;
 2: len 7; hex b60000019d0110; asc        ;;

間隙鎖

間隙鎖是加在一個間隙上的鎖闯割,這個間隙在兩個索引之間,也可能在第一個索引之前或者最后一個索引之后竿拆。舉例來說宙拉,SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;阻止了其他事務向表中插入一條c1的值為15的記錄,不管是否已經(jīng)存在這樣一條記錄丙笋,因為這個范圍之內(nèi)的所有記錄都被鎖住了谢澈。

一個間隙可能包括了一個索引值,或者包括多個御板,也可能一個都沒有锥忿。

間隙鎖是權(quán)衡了性能和并發(fā)能力的一個折中選擇,在某些隔離級別中使用了間隙鎖稳吮。

當使用一個唯一索引去查找唯一的一行記錄時是用不上間隙鎖的(不包括那種使用多個列成員來作為查找條件,同時這些列被定義為唯一索引井濒。這種情況下仍然會產(chǎn)生間隙鎖)灶似。舉例來說,如果id這一列是唯一索引瑞你,那么如下的語句將會使用記錄鎖來鎖住id為100的記錄酪惭,而不關(guān)心是否有其他事務在之前的間隙中插入數(shù)據(jù):

SELECT * FROM child WHERE id = 100;

如果id不是索引,或者不是唯一索引者甲,那么這條語句就會鎖住之前的間隙春感。

值得注意的是,兩種類型沖突的鎖是可以同時加在一個間隙上虏缸。舉例來說鲫懒,事務A在一個間隙上加了一個共享間隙鎖(gap S-lock),同時事務B在同一個間隙上加了一個排它間隙鎖(gap X-lock)刽辙。這種情況是允許的窥岩,因為如果一條記錄被刪除了,那么不同事務加在這個記錄左右兩邊的的間隙鎖必須合并(此處翻譯可能有誤)宰缤。

在InnoDB中颂翼,間隙鎖是"purely inhibitive"(不知如何翻譯)晃洒,也就是說間隙鎖只會阻止其他事務往間隙中插入數(shù)據(jù)。間隙鎖不阻止不同的事務在同一個間隙上加鎖朦乏。因此球及,間隙排它鎖(gap X-lock)和間隙共享鎖(gap S-lock)的效果是一樣的。

可以顯式禁止間隙鎖呻疹。將事務隔離級別設置為READ COMMITTED或者將系統(tǒng)配置innodb_locks_unsafe_for_binlog設置生效(不推薦這么搞)吃引,可以禁止使用間隙鎖艰管。這種情況下圆裕,間隙鎖只會用來做外鍵約束檢查和重復key檢查。

使用READ COMMITTED隔離級別或者將系統(tǒng)配置innodb_locks_unsafe_for_binlog設置生效還有其他兩個影響得运。當MySQL計算完WHERE語句后姑蓝,會釋放記錄鎖鹅心。對于UPDATE語句,InnoDB會做"半一致性(semi-consistent)"讀纺荧,它返回最近一次提交版本的記錄給MySQL旭愧,然后MySQL會決定這個記錄是否和UPDATE語句的WHERE條件匹配。(這段也不是很懂-_-||)

Next-Key鎖

Next-Key Lock是記錄鎖和間隙鎖的結(jié)合產(chǎn)物宙暇。

在查找和遍歷一個表的索引時输枯,InnoDB會做行級別的鎖,它對遇到的索引記錄加上共享鎖或者排它鎖占贫。因此行鎖實際上就是對索引加的鎖桃熄。在索引記錄上加的next-key lock會影響這個索引之前的間隙。意思就是型奥,一個next-key lock是一個索引上的鎖外加這個索引之前那部分間隙的鎖瞳收。如果一個會話在記錄R的索引上加了共享鎖或者排它鎖,那么其他會話不能在這個記錄R之前(按照索引順序)的間隙中插入記錄厢汹。

假設索引中包含了10,11,13,20這幾個值螟深。對于這個索引,可能的next-key lock會覆蓋如下幾個間隙烫葬,原括弧表示開區(qū)間界弧,方括弧表示閉區(qū)間:

(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)

對于最后一個間隙,next-key lock鎖住了最大的索引值之后的間隙搭综,以及一個偽索引值垢箕,這個索引值比所有的索引都大。這個偽索引實際上是不存在的兑巾,所以nex-key lock只是鎖住了最大索引值后面的間隙舰讹。

默認情況下,InnoDB工作在REPEATABLE READ級別下闪朱,同時innodb_locks_unsafe_for_binlog沒有設置為生效月匣。在這種情況下钻洒,InnoDB在查找和遍歷索引時會使用next-key lock,也就防止了幻行(查看Phantom Rows)锄开。

使用SHOW ENGINE INNODB STATUS命令以及InnoDB monitor可以查看next-key鎖素标,如下:

RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t` 
trx id 10080 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 8000000a; asc     ;;
 1: len 6; hex 00000000274f; asc     'O;;
 2: len 7; hex b60000019d0110; asc        ;;

插入意向鎖

插入意向鎖是一種間隙鎖,INSERT操作在插入行之前萍悴,會加一個插入意向鎖头遭。這個鎖顯示了這樣一種意圖:在插入數(shù)據(jù)時,多個事務如果向同一個間隙中插入數(shù)據(jù)癣诱,但是并不是插入同一個位置的數(shù)據(jù)计维,那么這些事務就不需要互相等待對方完成。假設有索引值4和7撕予,現(xiàn)在又兩個事務分別要插入5和6鲫惶,那么這兩個事務各自給4和7之間的間隙加上插入意向鎖,然后給待插入的行上加排它鎖实抡,他們不會阻塞彼此欠母,因為插入的行沒有沖突。

下面的例子展示了事務在獲取行的排它鎖之前吆寨,先加上了插入意向鎖赏淌。這個例子包括了兩個客戶請求,A和B啄清。

客戶A創(chuàng)建了一個有索引的表六水,插入了兩條數(shù)據(jù)(90和102),然后啟動一個事務辣卒,給ID大于100的行加了排它鎖掷贾。這個排它鎖包括了在記錄102之前的間隙:

mysql> CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;
mysql> INSERT INTO child (id) values (90),(102);

mysql> START TRANSACTION;
mysql> SELECT * FROM child WHERE id > 100 FOR UPDATE;
+-----+
| id  |
+-----+
| 102 |
+-----+

客戶B啟動一個事務,向這個間隙中插入記錄添寺。這個事務在等待獲取排他鎖之前胯盯,會先獲取一個插入意向鎖懈费。

mysql> START TRANSACTION;
mysql> INSERT INTO child (id) VALUES (101);

使用SHOW ENGINE INNODB STATUS命令以及InnoDB monitor可以查看插入意向鎖计露,如下:

RECORD LOCKS space id 31 page no 3 n bits 72 index `PRIMARY` of table `test`.`child`
trx id 8731 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 80000066; asc    f;;
 1: len 6; hex 000000002215; asc     " ;;
 2: len 7; hex 9000000172011c; asc     r  ;;...

AUTO-INC 鎖

AUTO-INC鎖是一個特殊的表級別鎖,當事務向一個帶有AUTO_INCREMENT列成員的表中插入數(shù)據(jù)時憎乙,會先加一個AUTO-INC鎖票罐。最簡單的情況下,如果一個事務正在向表中插入數(shù)據(jù)泞边,那么其他的想要插入數(shù)據(jù)的事務必須等待该押,這樣前面那個事務插入的數(shù)據(jù)才會有一個連續(xù)的primary key。

配置項innodb_autoinc_lock_mode控制著AUTO-INC鎖使用的算法阵谚。允許你自己選擇如何在插入操作的可預期自增序列以及并行能力中進行權(quán)衡折衷蚕礼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末烟具,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子奠蹬,更是在濱河造成了極大的恐慌朝聋,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件囤躁,死亡現(xiàn)場離奇詭異冀痕,居然都是意外死亡,警方通過查閱死者的電腦和手機狸演,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門言蛇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宵距,你說我怎么就攤上這事腊尚。” “怎么了消玄?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵跟伏,是天一觀的道長。 經(jīng)常有香客問我翩瓜,道長受扳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任兔跌,我火速辦了婚禮勘高,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘坟桅。我一直安慰自己华望,他們只是感情好,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布仅乓。 她就那樣靜靜地躺著赖舟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪夸楣。 梳的紋絲不亂的頭發(fā)上宾抓,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機與錄音豫喧,去河邊找鬼石洗。 笑死,一個胖子當著我的面吹牛紧显,可吹牛的內(nèi)容都是我干的讲衫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼孵班,長吁一口氣:“原來是場噩夢啊……” “哼涉兽!你這毒婦竟也來了招驴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤枷畏,失蹤者是張志新(化名)和其女友劉穎忽匈,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矿辽,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡丹允,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了袋倔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雕蔽。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖宾娜,靈堂內(nèi)的尸體忽然破棺而出批狐,到底是詐尸還是另有隱情,我是刑警寧澤前塔,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布嚣艇,位于F島的核電站,受9級特大地震影響华弓,放射性物質(zhì)發(fā)生泄漏食零。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一寂屏、第九天 我趴在偏房一處隱蔽的房頂上張望贰谣。 院中可真熱鬧,春花似錦迁霎、人聲如沸吱抚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秘豹。三九已至,卻和暖如春昌粤,著一層夾襖步出監(jiān)牢的瞬間既绕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工婚苹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留岸更,地道東北人鸵膏。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓膊升,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谭企。 傳聞我的和親對象是個殘疾皇子廓译,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容