InnoDB 使用一種稱為 Next-Key Locking 的鎖機制來解決幻讀問題。幻讀發生在一個事務在讀取某個范圍內的記錄時,另一個事務在這個范圍內插入新的記錄。InnoDB 的 Next-Key Locking 結合了行鎖(Row Lock)和間隙鎖(Gap Lock),確保在執行范圍查詢時能夠鎖定現有記錄以及它們之間的間隙,從而防止其他事務在該范圍內插入新的記錄。
Next-Key Locking 機制
Next-Key Locking 是一種在索引記錄上應用的鎖機制,它鎖住的并不僅僅是索引記錄本身,還包括索引記錄之間的間隙。這種機制可以防止其他事務在鎖定的范圍內插入新的記錄。
具體例子
假設你有一個包含以下記錄的表 employees
:
CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(100)
);INSERT INTO employees (id, name) VALUES (1, 'Alice'), (3, 'Bob'), (5, 'Charlie');
在使用可重復讀(REPEATABLE READ)隔離級別時,InnoDB 如何避免幻讀?考慮以下兩個事務:
- 事務 A:執行一個范圍查詢。
- 事務 B:在事務 A 的范圍內插入新的記錄。
事務 A
START TRANSACTION;
SELECT * FROM employees WHERE id BETWEEN 1 AND 5;
當事務 A 執行上述查詢時,InnoDB 會對滿足條件的所有記錄(id=1
, id=3
, id=5
)以及這些記錄之間的間隙((1,3)
, (3,5)
, (5,∞)
)加鎖。
事務 B
START TRANSACTION;
INSERT INTO employees (id, name) VALUES (2, 'David');
由于事務 A 已經鎖定了 id
范圍 [1,5]
及其間隙,所以事務 B 嘗試在范圍 [1,3]
的間隙中插入 id=2
的新記錄時會被阻塞,直到事務 A 提交或回滾。
示例演示
創建表和插入數據
CREATE TABLE employees (id INT PRIMARY KEY,name VARCHAR(100)
);INSERT INTO employees (id, name) VALUES (1, 'Alice'), (3, 'Bob'), (5, 'Charlie');
事務 A
START TRANSACTION;
SELECT * FROM employees WHERE id BETWEEN 1 AND 5; -- Next-Key Locking 在索引記錄及其間隙上加鎖
事務 B
START TRANSACTION;
INSERT INTO employees (id, name) VALUES (2, 'David'); -- 此操作會被阻塞,直到事務 A 提交或回滾
提交事務 A
COMMIT; -- 提交事務 A 后,事務 B 可以繼續執行
總結
InnoDB 使用 Next-Key Locking 機制通過結合行鎖和間隙鎖來解決幻讀問題。當一個事務在執行范圍查詢時,InnoDB 會鎖定查詢結果集中的每一條記錄以及這些記錄之間的間隙。這確保了在范圍內的任何插入操作都被阻塞,從而避免了幻讀。
這種鎖機制在可重復讀(REPEATABLE READ)隔離級別下有效地避免了幻讀,使得事務在讀取范圍內的數據時,不會因為其他事務的插入而讀取到新的“幻影”記錄。