什麼是間隙鎖

中心思想

間隙鎖鎖的是索引葉子節點的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沒有索引結構能存儲行鎖或者間隙鎖。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章