[mysql] [innodb]14.7.1 innodb 鎖
InnoDB的行級鎖,有兩種類型: shared (S) locks 和exclusive (X) locks。
shared (S) lock 允許持有鎖讀取行的事務(wù)。
exclusive (X) lock 允許事務(wù)在更新或刪除行時(shí)持有鎖。
如果事務(wù)T1持有在行r持有共享鎖,則事務(wù)T2?的對行鎖定的請求r將按以下方式處理:
T2對S鎖的請求可以立即被批準(zhǔn)。結(jié)果,T1和T2都在r上保持S鎖。
T2對X鎖的請求不能立即被批準(zhǔn)。
如果事務(wù)T1在行 r上持有獨(dú)占(X)鎖,則不能立即授予來自某些不同事務(wù)T2的請求,請求使用r 上的任一類型的鎖。相反,事務(wù)T2 必須等待事務(wù) T1 釋放其行 r 上的鎖。
意圖鎖? (Intention Locks)
InnoDB支持 多粒度 鎖定,允許行鎖和表鎖共存。例如,諸如鎖定表等LOCK TABLES ... WRITE?在指定的表上獲取獨(dú)占鎖(X 鎖)。為使在多個(gè)粒度級別鎖定,InnoDB 使用意圖鎖。意圖鎖是表級鎖,用于指示事務(wù)以后需要哪種類型的鎖(共享或獨(dú)占鎖),用于表中的行。有兩種類型的意向鎖:
意向共享鎖(IS) 表示事務(wù)打算對表中的單個(gè)行設(shè)置共享鎖。
意向獨(dú)占鎖 (IX) 表示事務(wù)打算對表中的單個(gè)行設(shè)置獨(dú)占鎖。
例如,SELECT ... LOCK IN SHARE MODE?設(shè)置是鎖定,并SELECT ... FOR UPDATE設(shè)置 IX 鎖。
意圖鎖定協(xié)議如下:
在事務(wù)可以獲取表中行上的共享鎖之前,它必須首先獲取IS 鎖或表上的更強(qiáng)鎖。
在事務(wù)可以獲取表中行的獨(dú)占鎖之前,它必須首先獲取表上的 IX鎖。
表級鎖類型兼容性總結(jié)如下矩陣。
Ⅹ
Ⅸ
S
IS
Ⅹ
沖突
沖突
沖突
沖突
Ⅸ
沖突
兼容
沖突
兼容
S
沖突
沖突
兼容
兼容
IS
沖突
兼容
兼容
兼容
如果請求事務(wù)與現(xiàn)有鎖兼容,則向請求事務(wù)授予鎖;如果與現(xiàn)有鎖沖突,則不授予請求事務(wù)。事務(wù)等待,直到釋放沖突的現(xiàn)有鎖。如果鎖請求與現(xiàn)有鎖沖突,并且由于會(huì)導(dǎo)致死鎖而發(fā)生錯(cuò)誤。
意圖鎖不會(huì)阻止除全表請求以外的任何請求(例如,?LOCK TABLES ... WRITE)。意圖鎖的主要目的是顯示某人正在鎖定一行,或要鎖定表中的一行。
意向鎖的事務(wù)數(shù)據(jù)與 以下通過SHOW ENGINE INNODB STATUS? 及 InnoDB monitor 輸出類似的:
TABLE LOCK table `test`.`t` trx id 10080 lock mode IX
記錄鎖(Record Locks)
記錄鎖是在索引上的鎖。例如,從 t 中選擇 c1,其中 c1 = 10 用于更新;防止任何其他事務(wù)插入、更新或刪除 t.c1值為10的行。
記錄鎖始終鎖定索引記錄,即使定義表時(shí)沒有索引。對于此類情況,InnoDB 創(chuàng)建一個(gè)隱藏的群集索引,并使用此索引進(jìn)行記錄鎖定。參見Section?14.6.2.1, “Clustered and Secondary Indexes”。
記錄鎖如下所示:
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 ;;
間隔鎖(Gap Locks)
間隔鎖是索引記錄之間間隔的鎖,或在第一個(gè)索引記錄之前或之后對間隔的鎖。例如,從 t 中選擇 c1,其中 c1 介于 10 和 20 之間進(jìn)行更新;防止其他事務(wù)將值 15 插入列 t.c1,無論列中是否已經(jīng)存在任何此類值,因?yàn)榉秶鷥?nèi)所有現(xiàn)有值之間的間隔都已鎖定。
間隔可能跨越單個(gè)索引值、多個(gè)索引值,甚至為空。
間隔鎖是性能和并發(fā)之間的權(quán)衡的一部分,用于某些事務(wù)隔離級別,而不是其他事務(wù)隔離級別。
對于使用唯一索引鎖定行以搜索唯一行的語句,不需要間隔鎖定。(這不包括搜索條件僅包含多列唯一索引的一些列的情況;在這種情況下,確實(shí)會(huì)發(fā)生間隔鎖定。例如,如果id列具有唯一的索引,則以下語句僅對ID 值為 100 的行使用索引記錄鎖,并且其他會(huì)話是否在上一個(gè)間隔中插入行并不重要:
SELECT * FROM child WHERE id = 100;
如果id 無索引或具有非唯一索引,則語句會(huì)鎖定前面的間隔。
這里還值得注意的是,沖突鎖可以由不同的事務(wù)在間隔上持有。例如,事務(wù) A 可以在間隔上保留共享間隔鎖(間隔 S 鎖),而事務(wù) B 在相同間隔上保留獨(dú)占間隔鎖(間隔 X 鎖)。允許沖突間隙鎖的原因是,如果從索引中清除記錄,則必須合并不同事務(wù)在記錄上持有的間隙鎖。
InnoDB 中的間隔鎖是"純粹抑制的",這意味著它們的唯一目的是防止其他事務(wù)插入間隔。間隔鎖可以共存。一個(gè)事務(wù)獲取的間隔鎖不會(huì)阻止另一個(gè)事務(wù)對同一間隔進(jìn)行間隔鎖。共享間隔鎖和獨(dú)占間隔鎖之間沒有區(qū)別。它們不相互沖突,并且執(zhí)行相同的功能。
可以顯式禁用間隔鎖定。如果將事務(wù)隔離級別更改為"READ COMMITTED?"或啟用系統(tǒng)innodb_locks_unsafe_for_binlog(現(xiàn)在已棄用),則將發(fā)生這種情況。在這些情況下,間隔鎖定將禁用用于搜索和索引掃描,并且僅用于外鍵約束檢查和重復(fù)鍵檢查。
使用"READ COMMITTED?"隔離級別或啟用"innodb_locks_unsafe_for_binlog。 ??在 Mysql 評估 WHERE 條件后,將釋放非匹配行的記錄鎖。對于UPDATE ?語句,InnoDB執(zhí)行"semi-consistent"讀取,以便它將最新的提交版本返回到 Mysql,以便 MySQL 可以確定行是否與 UPDATE 的 WHERE 條件匹配。
Next-Key Locks
Next-Key Locks 是索引記錄上的記錄鎖和索引記錄之前間斷鎖定的組合。
InnoDB 執(zhí)行行級鎖定的方式是,在搜索或掃描表索引時(shí),它會(huì)在它遇到的索引記錄上設(shè)置共享鎖或獨(dú)占鎖。因此,行級鎖實(shí)際上是索引記錄鎖。索引記錄的Next-Key Locks 鎖也會(huì)影響索引記錄前的"間斷"。也就是說,Next-Key Locks 是索引記錄鎖,外加索引記錄之前間斷的間斷鎖。如果一個(gè)會(huì)話在索引中對記錄R 具有共享或獨(dú)占鎖,則另一個(gè)會(huì)話無法在索引順序 R 之前在間斷中插入新的索引記錄。
假設(shè)索引包含值 10、11、13 和 20。此索引的可能Next-Key Locks涵蓋以下間隔,其中圓形括號(hào)表示間隔終結(jié)點(diǎn)的排除,方括號(hào)表示包含終結(jié)點(diǎn):
(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)
對于最后一個(gè)間隔,Next-Key Locks 鎖定索引中最大值上方的間隔和"supremum"偽記錄的值高于索引中實(shí)際值的任何值。supremum 不是真正的索引記錄,因此,實(shí)際上,此 Next-Key Locks? 僅鎖定最大索引值之后的差距。
默認(rèn)情況下,InnoDB 在 REPEATABLE READ 級別中運(yùn)行。在這種情況下,InnoDB 使用Next-Key Locks進(jìn)行搜索和索引掃描,從而防止幻行(see?Section?14.7.4, “Phantom Rows”)。
Next-Key Locks :
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è)置的間斷鎖類型。此鎖表示有意插入,以便插入到同一索引間斷中的多個(gè)事務(wù),如果它們未在間斷中的相同位置插入,就無需相互等待。假設(shè)有值為 4 和 7 的索引記錄。嘗試分別插入值 5 和 6 的單獨(dú)事務(wù),在獲取插入行上的獨(dú)占鎖之前,每個(gè)事務(wù)將 4 和 7 之間的間斷插入意圖鎖鎖定,但不會(huì)相互阻塞,因?yàn)樾惺欠菦_突的。
下面的示例演示在獲取插入記錄上的獨(dú)占鎖之前獲取插入意圖鎖的事務(wù)。該示例涉及兩個(gè)客戶端,A 和 B。
客戶端 A 創(chuàng)建一個(gè)包含兩個(gè)索引記錄(90 和 102)的表,然后啟動(dòng)一個(gè)事務(wù),該事務(wù)對 ID 大于 100 的索引記錄進(jìn)行獨(dú)占鎖。獨(dú)占鎖包括記錄 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 開始事務(wù),將記錄插入間隙。事務(wù)在等待獲取獨(dú)占鎖時(shí)采用插入意圖鎖。
mysql> START TRANSACTION;
mysql> INSERT INTO child (id) VALUES (101);
插入意圖鎖
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 鎖是事務(wù)插入具有包含任何列的表所AUTO_INCREMENT鎖。在最簡單的情況下,如果一個(gè)事務(wù)將值插入表中,任何其他事務(wù)必須等待在該表中執(zhí)行自己的插入,以便第一個(gè)事務(wù)插入的行接收連續(xù)的主要鍵值。
"innodb_autoinc_lock_mode配置選項(xiàng)控制用于自動(dòng)增量鎖定的算法。它允許您選擇如何在自動(dòng)遞增值的可預(yù)測序列和插入操作的最大并發(fā)性之間進(jìn)行權(quán)衡。
有關(guān)詳細(xì)信息,see?Section?14.6.1.6, “AUTO_INCREMENT Handling in InnoDB”。
空間索引的謂詞鎖(Predicate Locks for Spatial Indexes)
InnoDB支持包含空間列的列的空間索引(參見第 11.4.8 節(jié)"優(yōu)化空間分析")。
要處理涉及SPATIAL索引的操作的鎖定,下鍵鎖定不能很好地支持可重復(fù)讀取或可序列化事務(wù)隔離級別。多維數(shù)據(jù)中沒有絕對排序概念,因此不清楚哪個(gè)是"下一個(gè)"鍵。
若要支持具有 SPATIAL 索引的表的隔離級別,InnoDB 使用謂詞鎖。SPATIAL 索引包含最小邊界矩形 (MBR) 值,因此 InnoDB 通過設(shè)置用于查詢的 MBR 值的謂詞鎖來強(qiáng)制索引上一致的讀取。其他事務(wù)無法插入或修改與查詢條件匹配的行。
MySQL 數(shù)據(jù)庫
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。