詳解 MySql InnoDB 中的三種行鎖(記錄鎖、間隙鎖與臨鍵鎖)
前言
InnoDB 通過 MVCC 和 NEXT-KEY Locks,解決了在可重複讀的事務隔離級別下出現幻讀的問題。MVCC 我先挖個坑,日後再細講,這篇文章我們主要來談談那些可愛的鎖。
什麼是幻讀?
幻讀是在可重複讀的事務隔離級別下會出現的一種問題,簡單來說,可重複讀保證了當前事務不會讀取到其他事務已提交的 UPDATE 操作。但同時,也會導致當前事務無法感知到來自其他事務中的 INSERT 或 DELETE 操作,這就是幻讀。
關於行鎖我們要知道的
行鎖在 InnoDB 中是基於索引實現的,所以一旦某個加鎖操作沒有使用索引,那麼該鎖就會退化為表鎖。
可愛的鎖
記錄鎖(Record Locks)
顧名思義,記錄鎖就是為某行記錄加鎖,它封鎖該行的索引記錄:
– id 列為主鍵列或唯一索引列
SELECT * FROM table WHERE id = 1 FOR UPDATE;
複製程式碼
id 為 1 的記錄行會被鎖住。
需要注意的是:id 列必須為唯一索引列或主鍵列,否則上述語句加的鎖就會變成臨鍵鎖。
同時查詢語句必須為精準匹配(=),不能為 >、<、like等,否則也會退化成臨鍵鎖(感謝評論區 @decodes 提醒)。
其他實現
在通過 主鍵索引 與 唯一索引 對資料行進行 UPDATE 操作時,也會對該行資料加記錄鎖:
– id 列為主鍵列或唯一索引列
UPDATE SET age = 50 WHERE id = 1;
複製程式碼
間隙鎖(Gap Locks)
間隙鎖基於非唯一索引,它鎖定一段範圍內的索引記錄。間隙鎖基於下面將會提到的Next-Key Locking 演算法,請務必牢記:使用間隙鎖鎖住的是一個區間,而不僅僅是這個區間中的每一條資料。
SELECT * FROM table WHERE id BETWEN 1 AND 10 FOR UPDATE;
複製程式碼
即所有在(1,10)區間內的記錄行都會被鎖住,所有id 為 2、3、4、5、6、7、8、9 的資料行的插入會被阻塞,但是 1 和 10 兩條記錄行並不會被鎖住。
除了手動加鎖外,在執行完某些 SQL 後,InnoDB 也會自動加間隙鎖,這個我們在下面會提到。
臨鍵鎖(Next-Key Locks)
Next-Key 可以理解為一種特殊的間隙鎖,也可以理解為一種特殊的演算法。通過臨建鎖可以解決幻讀的問題。 每個資料行上的非唯一索引列上都會存在一把臨鍵鎖,當某個事務持有該資料行的臨鍵鎖時,會鎖住一段左開右閉區間的資料。需要強調的一點是,InnoDB 中行級鎖是基於索引實現的,臨鍵鎖只與非唯一索引列有關,在唯一索引列(包括主鍵列)上不存在臨鍵鎖。
假設有如下表:
MySql,InnoDB,Repeatable-Read:table(id PK, age KEY, name)
id age name
1 10 Lee
3 24 Soraka
5 32 Zed
7 45 Talon
該表中 age 列潛在的臨鍵鎖有:
(-∞, 10],
(10, 24],
(24, 32],
(32, 45],
(45, +∞],
在事務 A 中執行如下命令:
– 根據非唯一索引列 UPDATE 某條記錄
UPDATE table SET name = Vladimir WHERE age = 24;
– 或根據非唯一索引列 鎖住某條記錄
SELECT * FROM table WHERE age = 24 FOR UPDATE;
複製程式碼
不管執行了上述 SQL 中的哪一句,之後如果在事務 B 中執行以下命令,則該命令會被阻塞:
INSERT INTO table VALUES(100, 26, ‘Ezreal’);
複製程式碼
很明顯,事務 A 在對 age 為 24 的列進行 UPDATE 操作的同時,也獲取了 (24, 32] 這個區間內的臨鍵鎖。
不僅如此,在執行以下 SQL 時,也會陷入阻塞等待:
INSERT INTO table VALUES(100, 30, ‘Ezreal’);
複製程式碼
那最終我們就可以得知,在根據非唯一索引 對記錄行進行 UPDATE \ FOR UPDATE \ LOCK IN SHARE MODE 操作時,InnoDB 會獲取該記錄行的 臨鍵鎖 ,並同時獲取該記錄行下一個區間的間隙鎖。
即事務 A在執行了上述的 SQL 後,最終被鎖住的記錄區間為 (10, 32)。
總結
InnoDB 中的行鎖的實現依賴於索引,一旦某個加鎖操作沒有使用到索引,那麼該鎖就會退化為表鎖。
記錄鎖存在於包括主鍵索引在內的唯一索引中,鎖定單條索引記錄。
間隙鎖存在於非唯一索引中,鎖定開區間範圍內的一段間隔,它是基於臨鍵鎖實現的。
臨鍵鎖存在於非唯一索引中,該型別的每條記錄的索引上都存在這種鎖,它是一種特殊的間隙鎖,鎖定一段左開右閉的索引區間。
相關文章
- MySQL記錄鎖、間隙鎖、臨鍵鎖小案例演示MySql
- InnoDB常用鎖總結(行鎖、間隙鎖、臨鍵鎖、表鎖)
- MySQL 行級鎖之 間隙鎖、臨鍵鎖MySql
- 一文搞懂MySQL行鎖、表鎖、間隙鎖詳解MySql
- MySQL行鎖、表鎖、間隙鎖,你都瞭解嗎MySql
- MySQL鎖:03.InnoDB行鎖MySql
- MySQL innodb 的間隙鎖定(next-key locking)MySql
- 間隙鎖
- MySQL/InnoDB中,樂觀鎖、悲觀鎖、共享鎖、排它鎖、行鎖、表鎖、死鎖概念的理解MySql
- MySQL鎖:InnoDB行鎖需要避免的坑MySql
- mysql鎖之三種行級鎖介紹MySql
- MySQL鎖(讀鎖、共享鎖、寫鎖、S鎖、排它鎖、獨佔鎖、X鎖、表鎖、意向鎖、自增鎖、MDL鎖、RL鎖、GL鎖、NKL鎖、插入意向鎖、間隙鎖、頁鎖、悲觀鎖、樂觀鎖、隱式鎖、顯示鎖、全域性鎖、死鎖)MySql
- MySQL 悲觀鎖與樂觀鎖的詳解MySql
- 詳解 MySql InnoDB 中意向鎖的作用MySql
- MySQL InnoDB 中的鎖機制MySql
- 死鎖問題排查過程-間隙鎖的復現以及解決
- Mysql研磨之InnoDB行鎖模式MySql模式
- Mysql學習筆記-臨鍵鎖實驗MySql筆記
- MySQL 透過 Next-Key Locking 技術(行鎖+間隙鎖)避免幻讀問題MySql
- MySQL全域性鎖、表鎖以及行鎖MySql
- Mysql innodb引擎(二)鎖MySql
- 三分鐘入門 InnoDB 儲存引擎中的表鎖和行鎖儲存引擎
- Java鎖最全詳解:樂觀鎖/悲觀鎖+公平鎖/非公平鎖+獨享鎖/共享鎖Java
- Java 中15種鎖的介紹:公平鎖,可重入鎖,獨享鎖,互斥鎖,樂觀鎖,分段鎖,自旋鎖等等Java
- MySQL鎖(四)行鎖的加鎖規則和案例MySql
- 【問答分享第一彈】MySQL鎖總結:MySQL行鎖、表鎖、排他鎖、共享鎖的特點MySql
- InnoDB意向鎖和插入意向鎖
- MySQL優化篇系列文章(二)——MyISAM表鎖與InnoDB鎖問題MySql優化
- mysql鎖之死鎖MySql
- InnoDB儲存引擎鎖機制(三、鎖的演算法)儲存引擎演算法
- MySQL MyISAM引擎的讀鎖與寫鎖MySql
- Java 種15種鎖的介紹:公平鎖,可重入鎖,獨享鎖,互斥鎖等等Java
- Java 種15種鎖的介紹:公平鎖,可重入鎖,獨享鎖,互斥鎖等等...Java
- MySQL鎖詳解!(轉載)MySql
- MySQL 行鎖MySql
- MySQL -- 行鎖MySql
- MySQL索引失效行鎖變表鎖MySql索引
- mysql行鎖和死鎖檢測MySql