什么是間隙鎖


此文轉載自:https://blog.csdn.net/qq_21729419/article/details/113643359

中心思想

間隙鎖鎖的是索引葉子節點的next指針。

意義

解決了mysql RR級別下是幻讀的問題。

快照讀

在RR隔離級別下:快照讀有可能讀到數據的歷史版本,也有可能讀到數據的當前版本。所以快照讀無需用鎖也不會發生幻讀的情況。

當前讀

當前讀:select…lock in share mode,select…for update
當前讀:update,delete,insert

讀取的是記錄的最新版本,所以所以就需要通過加鎖(行鎖 間隙鎖 表鎖)的方式,使得被當前讀讀過的數據不能被新增修改或者刪除,換句話說再來一次當前讀要返回相同的數據。

為什么需要間隙鎖

數據表

CREATE TABLE `z` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `b` int(11) DEFAULT NULL,
  `c` int(255) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `b` (`b`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;


INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('1', '1', '0');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('3', '6', '1');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('5', '4', '2');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('7', '8', '3');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('8', '10', '4');

索引B結構

鎖加在哪里

begin; select * from z where b = 6 for update;

這條sql語句之后看看我們 需要做什么才能保證不發生幻讀。

1不能插入b為6的數據

2不能刪除b為6的數據

3不能修改b為6的數據

4不能把別的數據修改為b為6

突然一看挺復雜的,這個鎖要怎么加呢,mysql大牛靈機一動,給葉子節點5的next指針加鎖,給葉子節點3加行鎖,給葉子節點3的next指針加鎖。如下圖所示

這樣不就能把上述四個問題解決了么,兩個next指針鎖解決了插入b為6或者把別的數據修改為b為6,行鎖解決了修改b為6的行,但是呢也帶來一些明顯的副作用。

例如

INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('6', '4', '0'); 

 會bolck因為按照索引結構這條數據會插入到葉子結點5和3之間,會修改葉子節點5的next指針,雖然這條sql沒有破壞上述的4個紅色條件但是依然被阻塞了所以我叫它為副作用。

INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('4', '4', '0'); 

 插入成功因為這條數據會插入在1的后面5的前面。

現在大家是不是能理解間隙鎖的怪異行為了呢。

間隙鎖范圍

begin; 
select * from z where id=4 for update;

會鎖住主鍵索引葉子節點的3的next指針。(為啥呢,需要你自己畫主鍵索引的圖)

begin; 
select * from z where id=3 for update;

間隙鎖會退化為行鎖只鎖葉子節點3 ,為什么因為沒必要。不加間隙鎖也不會打破上述的紅色4個條件。

begin; 
select * from z where id>4 for update;

葉子節點3及之后所有節點會加行鎖並且他們的next指針會加鎖,

begin; 
select * from z where c=2 for update;

會發生鎖表,因為c沒有索引結構能存儲行鎖或者間隙鎖。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM