一、概念介紹
mysql鎖大類分為表鎖和行鎖,顧名思義表鎖是把整張表鎖住,行鎖粒度小一點,對行進行加鎖。同時,行鎖是針對索引列,有索引,才會有行鎖;注意,即使你沒有創建主鍵索引,mysql會創建一個隱藏的主鍵索引列。
為什么要了解鎖呢?
因為你需要當數據庫死鎖發生,事務阻塞,你需要知道是怎樣造成的,才能解決。
二、行鎖分類
1)共享鎖shared (S
) lock
在一個事務里查詢會持有共享鎖
2)排他鎖exclusive (X
) lock
在一個事務里刪除或者修改會持有排他鎖
3)間隙鎖gap lock
在事務級別為REPEATABLE-READ級別,才有間隙鎖;間隙鎖可以避免幻讀。注:如果加鎖列是唯一索引列或者主鍵列,間隙鎖會蛻化為記錄鎖,只鎖一行。
CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB;
INSERT INTO child VALUE(100,102);
數據100,102之間就是間隙,間隙加鎖就是間隙鎖;加鎖區間前開后開,如(100,102),不包括100,102
SESSION A
begin;
SELECT * FROM child WHERE between 100 AND 102 FOR UPDATE; 執行成功,給100和102之間的間隙加鎖;
SESSION B
INSERT INTO child VALUE(101);//block
SESSION A先執行,SESSION B會被阻塞,因為100和102之間的間隙被加鎖了
4)Record Lock記錄鎖
記錄鎖就是把一行鎖
5)Next-Key Lock
Next-Key Lock就是Record Lock+gap lock,加鎖前開后閉,如(100,102]
6)Insert Intention Lock
插入意向鎖,是一個特殊的gap lock,只會鎖住插入那一行;在執行insert操作會先獲取Insert Intention Lock;
注:插入意向鎖不會跟任何其他鎖互斥,除了表鎖和全局鎖;
三、表鎖分類
1)意向鎖
意向鎖分為意向共享鎖(IS)intention shared lock和意向排他鎖(IX)intention exclusive lock
意向共享鎖在獲取共享鎖之前會獲取意向排他鎖;意向排他鎖在獲取排他鎖之前會獲取意向排他鎖
意向鎖Intention Locks就是申明事務獲取哪種類型的鎖
SELECT ... LOCK IN SHARE MODE獲取IS鎖,SELECT ... FOR UPDATE獲取IX鎖,LOCK TABLES ... WRITE獲取X鎖,LOCK TABLES ... READ獲取S鎖,注:使用LOCK加鎖,必須用UNLOCK釋放鎖或者客戶端斷開連接釋放
下圖是意向鎖之間和共享鎖和排他鎖之間的互斥關系
X | IX | S | IS | |
X | Conflict | Conflict | Conflict | Conflict |
IX | Conflict | Compatible | Conflict | Compatible |
S | Conflict | Conflict | Compatible | Compatible |
IS | Conflict | Compatible | Compatible | Compatible |
2)metadata lock
訪問的時候會自動加上,就是表加上metadata lock鎖,DDL操作會被阻塞;注:MDL讀鎖跟表級寫鎖互斥,跟表級讀鎖不互斥
metadata lock簡稱MDL鎖,增刪改查加的MDL讀鎖,DDL操作加的是MDL寫鎖,MDL讀鎖不互斥,MDL寫鎖、讀寫鎖之間互斥.
注:metadata lock優先級最高,如果事務A得到MDL鎖,事務B要獲取MDL會被阻塞,事務C獲取意向鎖,阻塞;當事務A鎖釋放,鎖會優先被分配給事務B.
四、總結
1.插入、刪除和修改加的鎖類型都是排他鎖,刪除和修改是加的是next-key的排他鎖,插入是在索引上加一個記錄排他鎖。注:當插入發生a duplicate-key error,會設置一個共享鎖。
2.行鎖是在作用在索引上,如果一個表沒有索引和主鍵,mysql會創建一個隱藏的主鍵列;
3.在可重復讀級別才有間隙鎖和next key lock
4.事務一提交,鎖就會釋放
5.如果加鎖匹配不上任何索引,會對整個表加鎖
6.加鎖的基本單位為next-key lock,除了Insert操作
參考:https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html,https://dev.mysql.com/doc/refman/5.7/en/innodb-locks-set.html,https://dev.mysql.com/doc/refman/8.0/en/metadata-locking.html