文章翻譯自15.7.1 InnoDB Locking,其中全部鎖特性都以mysql-8.0版本爲準,其中包含的鎖種類以下:html
Innodb實現了標準的行級鎖,包括共享鎖和排它鎖兩種類型mysql
若是事務T1擁有行r上的共享鎖,那麼對於不一樣的事務T2的對行r上的請求,有如下處理方式:算法
若是事務T1擁有行r上的排它鎖,則對於不一樣的事務T2,不能授予其行r上的任何鎖,T2必須等待T1釋放其對行r的鎖定sql
InnoDB支持多種粒度的鎖定,來容許行鎖和表鎖同時存在,例如LOCK TABLE ... WRITE
語句能夠在指定的表上使用排它鎖。爲了實現多粒度鎖定,InnoDB使用了意向鎖數據庫
意向鎖是表級鎖,它表示一個事務稍後對錶中的行須要使用的鎖類型,意向鎖有兩種類型:併發
例如,SELECT ... FOR SHARE
會設置IS鎖,SELECT ... FOR UPDATE
會設置IX鎖性能
意向鎖的協議以下:spa
表級鎖的兼容性經過如下的矩陣進行了總結: 翻譯
意向鎖不會阻塞除全表請求外的任何內容(如LOCK TABLES ... WRITE
),意向鎖的主要目的是顯示某人正在或正要鎖定表中的行code
意向鎖鎖定的事務數據在SHOW ENGINE INNODB STATUS
和InnoDB監視器中輸出的內容大體是如下這種形式:
TABLE LOCK table `test`.`t` trx id 10080 lock mode IX
複製代碼
記錄鎖,是對索引記錄的鎖定。例如,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;
會阻止其餘事務的插入、更新,以及刪除t表中c1=10的行
即便表中沒有定義索引,記錄鎖也始終會鎖定索引記錄。在這種狀況下,InnoDB會建立一個隱藏的彙集索引,並使用此索引來進行記錄鎖定
記錄鎖鎖定的事務數據在SHOW ENGINE INNODB STATUS
和InnoDB監視器中輸出的內容大體是如下這種形式:
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;
會阻止其餘事務將值15插入到t.c1中,不管該列是否存在任何這樣的值,由於該範圍內的任何存在的值都會被鎖定
這個間隙可能會跨越單個索引、多個索引,甚至是空
間隙鎖是性能和併發能力之間的一些權衡,僅會做用於某些事務隔離級別
使用惟一索引來搜索惟一行的語句不會使用間隙鎖(不包括搜索條件僅包含多列惟一索引的某些列的狀況,在這種狀況下,仍是會使用間隙鎖),好比,若是id列使用了惟一索引,則如下語句僅使用對於id爲100的鎖使用索引記錄鎖,而不關心其餘的會話是否在前一個間隙中插入行:
SELECT * FROM child WHERE id = 100;
複製代碼
若是id列沒有索引,或使用的是非惟一索引,則該語句會鎖定前一個間隙
值得注意的是,互相沖突的鎖能夠經過不一樣的事務在間隙上保持,例如,事務A在間隙上保持共享的間隙鎖(間隙S鎖),事務B能夠在同一間隙上保持獨佔的間隙鎖(間隙X鎖)。容許互相沖突的間隙鎖的緣由是,若是從索引中清除記錄,則必須合併由不一樣事務保留在記錄上的間隙鎖
InnoDB的間隙鎖是「純粹的抑制」,這意味着間隙鎖的惟一目的是阻止其餘事務插入間隙。間隙鎖能夠共存,一個事務的間隙鎖不會阻止另外一個事務在同一個間隙上進行間隙鎖的鎖定,共享間隙鎖和排他間隙鎖之間沒有區別,彼此不衝突,它們擁有相同的功能
能夠經過明確的聲明來禁用間隙鎖,好比將事務隔離級別設置爲READ COMMITTED
。在這種狀況下,對於搜索和索引掃描會禁用間隙鎖,僅會做用於外鍵約束和重複鍵的檢查
使用READ COMMITTED
隔離級別還會有其餘影響,MySQL評估WHERE
條件後,會釋放不匹配行的記錄鎖。對於UPDATE
語句,InnoDB執行「半一致」讀取,使之能將最新的版本提交給MySQL,MySQL就能夠肯定該行是否與UPDATE
的WHERE
條件匹配
後鍵鎖,是索引記錄上的記錄鎖
和索引記錄以前的間隙鎖
的組合
InnoDB使用這樣一種方式來進行行級鎖定:當搜索或掃描表索引時,會在遇到的索引記錄上設置共享鎖或排它鎖,所以,行級鎖其實是索引記錄鎖
索引記錄上的後鍵鎖也會影響該索引記錄以前的「間隙」,也就是說後鍵鎖是索引記錄鎖加上該索引記錄以前的間隙上的間隙鎖。若是一個會話在索引中的記錄R上有共享鎖或排它鎖,則另外一個會話不能在索引順序中的R以前的間隙中插入新的索引記錄
假設索引中包含值十、十一、13,和20,此索引可能的後鍵鎖會覆蓋如下鍵值,其中圓括號表示排除的間隔端點,方括號表示包含的端點(即開集和閉集的概念):
(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)
複製代碼
對於最後一個間隔,後鍵鎖將間隙鎖定在索引中最大值之上,且僞記錄「supermum」的值高於索引中任何的實際值,supermun不是真正的索引記錄,所以,實際上這個後鍵鎖(指最後一個間隙的後鍵鎖)僅鎖定最大索引值以後的間隙
默認狀況下,InnoDB在REPEATABLE READ
隔離級別下運行,在這種狀況下,InnoDB使用後鍵鎖進行搜索和索引掃描,從而防止幻讀
後鍵鎖的事務數據在SHOW ENGINE INNODB STATUS
和InnoDB監視器中輸出的內容大體是如下這種形式:
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
操做設置的一種間隙鎖。該鎖表示以這種方式插入的意圖:若是插入到相同索引間隙中的多個事務,不插入間隙內的相同位置,則不須要等待彼此
假設存在值爲4和7的索引記錄,兩個單獨的事務分別嘗試插入值爲5和6的記錄,在獲取插入行的排他鎖以前,分別使用插入意向鎖來鎖定4到7之間的間隙,可是不會相互阻塞,由於行爲是不衝突的
如下示例演示了在獲取插入記錄的排它鎖以前,使用插入意向鎖來進行鎖定。該示例涉及兩個客戶端,分別是A和B
客戶端A建立了一個包含兩個索引記錄(99和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監視器中輸出的內容大體是如下這種形式:
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_INCREMENT
自增屬性的列中的事務鎖採用的特殊表級鎖。在最簡單的狀況下,若是一個事務正在向表中插入值,則其餘任何事務都必須等待該表執行本身的插入操做,以便被第一個事務插入的行接收到連續的主鍵值
innodb_autoinc_lock_mode
配置選項用來控制用於自增鎖定的算法,它容許您在可預測的自增值序列和插入操做的最大併發量之間權衡
InnoDB支持包含空間性列的SPATIAL
索引(參考11.5.9 Optimizing Spatial Analysis)
要處理涉及SPATIAL索引
的操做的鎖定,後鍵鎖不能很好地支持REPEATABLE READ
和SERIALIZABLE
事務隔離級別,多維數據中沒有絕對有序的概念,所以不能準確地判斷哪個是「後鍵」
爲了支持包含SPATIAL索引
的表的隔離級別,InnoDB使用了謂詞鎖
,SPATIAL索引
包含最小邊界矩形(MBR)值,所以InnoDB在用於查詢的MBR值上設置謂詞鎖來強制對索引進行一致性讀取,其餘事務沒法插入或修改與查詢條件匹配的行