原文地址:https://docs.oracle.com/cd/E17952_01/mysql-5.5-en/innodb-locking.html
本節(jié)介紹 InnoDB 的鎖類型:
- 共享和排他鎖(Shared and Exclusive Locks)
- 意向鎖(Intention Locks)
- 記錄鎖(Record Locks)
- 區(qū)間鎖 / 間隙鎖(Gap Locks)
- 意向插入鎖(Insert Intention Locks)
- 自增鎖(AUTO-INC Locks)
- Next-Key Locks
共享和排他鎖(Shared and Exclusive Locks)
InnoDB 實現(xiàn)了標準的行級鎖,分為兩種類型:共享(S
)鎖 和 排他(X
)鎖。
如果事務T1在行 r 上持有共享(S)鎖,則其他事務T2對行 r 的鎖的請求按如下方式處理:
- 可以立即授予T2對S鎖的請求。 結果,T1和T2都在r上持有S鎖。
- T2的X鎖定請求不能立即授予。
如果事務T1在行r上持有排他(X)鎖,則不能立即授予其他事務T2對r上任何類型的鎖請求。相反,T2必須等待T1釋放其對行r的鎖定。
意向鎖(Intention Locks)
InnoDB支持多種粒度的鎖,允許行鎖和表鎖共存。 例如 LOCK TABLES ... WRITE
等語句在指定的表上持有排他鎖(X 鎖)。 InnoDB用意向鎖來實現(xiàn)多粒度級別的鎖。意向鎖是表級鎖,表示事務稍后對表中的行進行加相關類型的鎖(共享或排他)。意向鎖有兩種類型:
- 意向共享鎖(intention shared lock, IS)表示事務打算在表中的各個行上設置共享鎖。
- 意向排他鎖(intention exclusive lock, IX)表示事務打算在表中的各個行上設置排他鎖。
例如 SELECT ... LOCK IN SHARE MODE
設置IS
鎖, SELECT ... FOR UPDATE
設置IX
鎖定。
意向鎖的規(guī)則如下:
- 事務在獲取表中某行的共享鎖之前,必須先獲取表上的 IS 鎖或類似的鎖。
- 事務在獲取表中某行的排他鎖之前,必須先獲取表上的 IX 鎖。
下面是表級鎖類型兼容性總結:
當前事務現(xiàn)有的鎖 / 其他事務的鎖請求 | X | IX | S | IS |
---|---|---|---|---|
X | 沖突 | 沖突 | 沖突 | 沖突 |
IX | 沖突 | 兼容 | 沖突 | 兼容 |
S | 沖突 | 沖突 | 兼容 | 兼容 |
IS | 沖突 | 兼容 | 兼容 | 兼容 |
如果事務請求的鎖與現(xiàn)有鎖兼容就授予鎖,如果沖突則不會。 事務會一直等到現(xiàn)有的鎖釋放。如果因為事務請求的鎖與現(xiàn)有的鎖沖突而無法授予,則可能會導致發(fā)生死鎖(deadlock)錯誤。
除全表請求之外,意向鎖不會阻塞任何事務(例如 LOCK TABLES ... WRITE
)。意向鎖的主要目的是表示某人正在鎖定行,或將要鎖定表中的行。
意向鎖的事務數據與 SHOW ENGINE INNODB STATUS
和 InnoDB monitor 輸出中的以下內容類似:
TABLE LOCK table `test`.`t` trx id 10080 lock mode IX
記錄鎖(Record Locks)
記錄鎖是對索引記錄的鎖定。 例如,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;
防止任何其他事務插入,更新或刪除 t.c1 的值為 10 的行。
即使表沒有定義索引,記錄鎖也能鎖定索引記錄。因為 InnoDB創(chuàng)建了一個隱藏的聚簇索引并使用此索引做記錄鎖。 請參見 第14.11.2.1節(jié)“聚簇和二級索引”。
記錄鎖的事務數據在SHOW ENGINE INNODB STATUS和InnoDB監(jiān)視器輸出中顯示類似于以下內容:
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 ;;
區(qū)間鎖 / 間隙鎖(Gap Locks)
區(qū)間鎖是鎖定索引記錄之間的區(qū)間,或鎖定在第一個或最后一個索引記錄之前的區(qū)間上。 例如,SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;
阻止其他事務將值15插入到列 t.c1 中,無論列中是否存在任何此類值,因為該范圍內所有現(xiàn)有值之間的區(qū)間都被鎖定。
區(qū)間可能跨越單個索引值,多個索引值,甚至可能為空。
區(qū)間鎖是性能和并發(fā)之間權衡的一部分,用于某些事務隔離級別而不是其他級別。
使用唯一索引(unique index )鎖定行以搜索唯一行的語句不需要區(qū)間鎖。(這不包括搜索條件僅包括多列唯一索引的一些列的情況; 在這種情況下,確實會發(fā)生區(qū)間鎖定。)例如,如果id
列具有唯一索引,則以下語句僅對id
值為100的行使用索引記錄鎖,并且其他會話是否在前一個間隙中插入行無關緊要:
SELECT * FROM child WHERE id = 100;
如果id
未編入索引或具有非唯一索引,則該語句會鎖定前一個區(qū)間。
這里還值得注意的是,不同的事務在相同區(qū)間上可以存在相互沖突的鎖類型。 例如,事務A可以在區(qū)間上持有共享區(qū)間鎖(區(qū)間S鎖),而事務B在同一區(qū)間上持有排他區(qū)間鎖(區(qū)間X鎖)。 允許區(qū)間鎖沖突的原因是,如果從索引中清除記錄,則必須合并由不同事務保留在記錄上的區(qū)間鎖。
在InnoDB中區(qū)間鎖被“抑制”了,這意味著它們的唯一目的是防止其他事務插入區(qū)間。區(qū)間鎖可以共存。一個事務占用的區(qū)間鎖定不會阻止另一個事務在同一個區(qū)間上進行區(qū)間鎖定。 共享和排他區(qū)間鎖之間沒有區(qū)別。它們彼此不沖突,它們執(zhí)行相同的功能。
如果將事務隔離級別更改為READ COMMITTED
或啟用系統(tǒng)變量innodb_locks_unsafe_for_binlog
,就可以明確禁用區(qū)間鎖。此時,搜索和索引掃描會禁用區(qū)間鎖定,只能用于外鍵約束檢查和重復鍵檢查。
使用 READ COMMITTED 隔離級別或啟用 innodb_locks_unsafe_for_binlog 還有其他影響。 MySQL評估 WHERE 條件后,將釋放非匹配行的記錄鎖。對于UPDATE 語句,InnoDB 執(zhí)行“半一致(semi-consistent)”讀取,以便將最新提交的版本返回給MySQL,以便MySQL可以確定該行是否與 UPDATE 的 WHERE 條件匹配。
Next-Key Locks
Next-Key鎖是索引記錄上的記錄鎖和索引記錄之前的區(qū)間上的區(qū)間鎖的組合。
InnoDB用以下方式執(zhí)行行級鎖定:當它搜索或掃描表索引時,它會在遇到的索引記錄上設置共享鎖或排它鎖。 因此,行級鎖實際上是索引記錄鎖。索引記錄上的Next-Key鎖也會影響該索引記錄之前的“區(qū)間”。也就是說,Next-Key鎖是索引記錄鎖加上索引記錄之前的區(qū)間上的區(qū)間鎖。如果一個會話在索引記錄R上具有共享鎖或排他鎖,則另一個會話不能在索引順序中的R之前的區(qū)間中插入新的索引記錄。
假設索引包含值10,11,13和20。此索引的可能的Next-Key鎖定包括以下間隔,其中圓括號表示排除區(qū)間端點,方括號表示包含端點:
(-∞, 10]
(10, 11]
(11, 13]
(13, 20]
(20, +∞)
對于最后一個區(qū)間,Next-Key 鎖將區(qū)間鎖定在索引中最大值之上,而“supremum”偽記錄的值高于索引中實際的任何值。supremum不是真正的索引記錄,因此,實際上,此Next-Key鎖僅鎖定最大索引值之后的間隙。
默認情況下,InnoDB 在 REPEATABLE READ (RR)
事務隔離級別運行,并禁用系統(tǒng)變量innodb_locks_unsafe_for_binlog
。在這種情況下,InnoDB 使用 Next-Key 鎖進行搜索和索引掃描,從而防止幻像行(參見 Section 14.8.4, “Phantom Rows”)。
Next-Key 鎖的事務數據與 SHOW ENGINE INNODB STATUS 和 InnoDB監(jiān)視器 輸出中的以下內容類似:
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 Intention Locks
待翻譯
AUTO-INC Locks
AUTO-INC 鎖是由插入到具有 AUTO_INCREMENT 列的表中的事務所采用的特殊表級鎖。在最簡單的情況下,如果一個事務正在向表中插入值,則任何其他事務必須等待對該表執(zhí)行自己的插入,以便第一個事務插入的行接收連續(xù)的主鍵值。
可以通過配置項 innodb_autoinc_lock_mode
調整自增鎖算法,例如:調整自增序列和插入操作的最大并發(fā)。