什么是間隙鎖又官?到底鎖了什么延刘?

MySQL 中關(guān)于gap lock(間隙鎖) 、 next-key lock(間隙鎖+行鎖) 的一個(gè)問(wèn)題

在學(xué)習(xí) MySQL 的過(guò)程中遇到的一個(gè)關(guān)于鎖的問(wèn)題六敬,包含多個(gè) MySQL 相關(guān)的知識(shí)碘赖;相關(guān)資料在文章末尾

問(wèn)題1描述

  • 表初始化
CREATE TABLE z (
  id INT PRIMARY KEY AUTO_INCREMENT,
  b  INT,
  KEY b(b)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

INSERT INTO z 
  (id, b)
VALUES 
  (1, 2),
  (3, 4),
  (5, 6),
  (7, 8),
  (9, 10);

當(dāng)前表中的數(shù)據(jù)為:


表z的數(shù)據(jù)
  • session A
BEGIN;
SELECT * FROM z WHERE b = 6 FOR UPDATE;
  • session B
INSERT INTO z VALUES (2, 4);/*success*/
INSERT INTO z VALUES (2, 8);/*blocked*/
INSERT INTO z VALUES (4, 4);/*blocked*/
INSERT INTO z VALUES (4, 8);/*blocked*/
INSERT INTO z VALUES (8, 4);/*blocked*/
INSERT INTO z VALUES (8, 8);/*success*/
INSERT INTO z VALUES (0, 4);/*blocked*/
INSERT INTO z VALUES (-1, 4);/*success*/

分別執(zhí)行 session B中的insert 會(huì)出現(xiàn)上述情況,為什么外构?

加鎖過(guò)程

  1. 在索引 b 上的等值查詢普泡,給索引 b 加上了 next-key lock (4, 6];索引向右遍歷审编,且最后一個(gè)值不滿足條件時(shí)退化為間隙鎖撼班;所以會(huì)再加上間隙鎖 (6,8);所以索引 b 上的 next-key lock 的范圍是(b=4,id=3)到(b=6,id=5)這個(gè)左開(kāi)右閉區(qū)間和(b=6,id=5)到(b=8,id=7)這個(gè)開(kāi)區(qū)間垒酬。(讀起來(lái)有點(diǎn)繞口砰嘁,看不懂的可以看下文中的圖)
  2. for update 會(huì)給 b = 6 這一行加上行鎖;因此 (b=6,id=5) 這一行上有行鎖

  • 這么看來(lái)上述語(yǔ)句都不在鎖的范圍內(nèi)勘究,為什么會(huì)被鎖

這個(gè)問(wèn)題其實(shí)是因?yàn)闆](méi)有理解索引的結(jié)構(gòu)矮湘,所以認(rèn)為所有值都不應(yīng)該被鎖

  • 如圖所示,此時(shí)索引 b 上的鎖:
索引 b 鎖范圍.png
  • 圖中綠色部分即為被鎖范圍口糕;索引會(huì)根據(jù) b 和 id 的值進(jìn)行排序缅阳,插入不同的值,鎖的范圍是不一樣的景描;分別插入 (b=4,id=2) 和(b=4,id=4)券时,插入的位置如圖所示:
(2,4)&(4,4)索引 b 鎖范圍.png
  • 因?yàn)樗饕怯行虻模藭r(shí)伏伯,由于記錄(b=4,id=3)的存在橘洞,(b=4,id=2)不在鎖的范圍內(nèi),可以插入说搅,但(b=4,id=4)在鎖的范圍內(nèi)炸枣,所以插入時(shí)需要等待鎖釋放,被 blocked
  • 對(duì)于其他(id,b)的值(2,8),(4,8),(8,4),(8,8)也是同樣的道理;因此适肠,得出以下結(jié)論:
    • id <= 2 時(shí)霍衫,b 索引鎖范圍為 (4,8]
    • 2 < id < 8 時(shí),b 索引鎖范圍為 [4,8]
    • a >= 8 時(shí)侯养,b 索引鎖范圍為 [4,8)
(2,8),(4,8),(8,4),(8,8)索引 b 鎖范圍.png
  • 但是敦跌,實(shí)踐發(fā)現(xiàn),當(dāng) id=0 時(shí)逛揩,被鎖的范圍為 [4,8)柠傍,這和我們得到的第一個(gè)結(jié)論(4,8]不一樣;此時(shí)分析得到的示意圖為:
(0,4),(0,8)索引 b 鎖范圍.png
  • 在 session A 中嘗試插入 (b=4, id=0)并查詢結(jié)果:
INSERT INTO z VALUES (0, 4);

SELECT * FROM z;
  • 此時(shí)辩稽,發(fā)現(xiàn)表中并沒(méi)有發(fā)現(xiàn) (b=4, id=0)這條記錄惧笛,但是多了 (b=4,id=10)這條;所以插入 (b=4, id=0)的時(shí)候真正插入的是 (b=4,id=10)這個(gè)值逞泄;這是因?yàn)槲覀冊(cè)趧?chuàng)建表的時(shí)候指定主鍵 id 的值 AUTO INCREMENT患整,當(dāng)插入的主鍵值為0的時(shí)候,會(huì)被替換為 AUTO_INCREMENT的值喷众,即10
(0,4)插入后查詢結(jié)果.png

No value was specified for the AUTO_INCREMENT column, so MySQL assigned sequence numbers automatically. You can also explicitly assign 0 to the column to generate sequence numbers, unless the NO_AUTO_VALUE_ON_ZERO SQL mode is enabled.

If the column is declared NOT NULL, it is also possible to assign NULL to the column to generate sequence numbers.

When you insert any other value into an AUTO_INCREMENT column, the column is set to that value and the sequence is reset so that the next automatically generated value follows sequentially from the largest column value.

  • 如果將主鍵修改為不自增履婉,插入 (b=4, id=0) 會(huì)得到這條記錄

問(wèn)題一的部分來(lái)自MySQL 中關(guān)于gap lock / next-key lock 的一個(gè)問(wèn)題


問(wèn)題2描述

問(wèn)題二部分來(lái)自什么是間隙鎖?到底鎖了什么斟览?

當(dāng)前表中的數(shù)據(jù)為:


表z的數(shù)據(jù)
  • session A
BEGIN;
SELECT * FROM z WHERE b = 6 FOR UPDATE;
  • session B
UPDATE z SET b = 7 WHERE id = 7;/*blocked*/
UPDATE z SET id = 6 WHERE id = 8;/*blocked*/

分別執(zhí)行 session B中的UPDATE會(huì)出現(xiàn)上述情況毁腿,為什么?

建表后苛茂,b字段上的2,4,6,8是以B+tree的數(shù)據(jù)結(jié)構(gòu)出現(xiàn)已烤,為了方便理解,這里我們不強(qiáng)調(diào)B+tree的結(jié)構(gòu)妓羊,強(qiáng)調(diào)有序胯究。索引b上的數(shù)據(jù)結(jié)圖如下所示:


b索引
  • 根據(jù)上文解釋的上鎖規(guī)則:

加鎖過(guò)程

  1. 在索引 b 上的等值查詢,給索引 b 加上了 next-key lock (4, 6]躁绸;索引向右遍歷裕循,且最后一個(gè)值不滿足條件時(shí)退化為間隙鎖臣嚣;所以會(huì)再加上間隙鎖 (6,8);所以索引 b 上的 next-key lock 的范圍是(b=4,id=3)到(b=6,id=5)這個(gè)左開(kāi)右閉區(qū)間和(b=6,id=5)到(b=8,id=7)這個(gè)開(kāi)區(qū)間剥哑。(讀起來(lái)有點(diǎn)繞口硅则,看不懂的可以看下文中的圖)
  2. for update 會(huì)給 b = 6 這一行加上行鎖;因此 (b=6,id=5) 這一行上有行鎖

鎖住的部分應(yīng)該如下圖所示

上鎖
  • 執(zhí)行UPDATE z SET b = 7 WHERE id = 7;株婴,會(huì)刪掉(b=8,id=7)的索引且新增(b=7,id=7)的索引怎虫,新增部分根據(jù)索引有序的規(guī)則,將會(huì)落在鎖住的部分區(qū)間困介,所以會(huì)被阻塞大审。
UPDATE z SET b = 7 WHERE id = 7;
  • 執(zhí)行UPDATE z SET id = 6 WHERE id = 8;,會(huì)將b索引上(b=8,id=8)葉子節(jié)點(diǎn)刪掉逻翁,并增加(b=8,id=6)的葉子節(jié)點(diǎn)饥努〖裼悖可以看到(b=8,id=6)的葉子節(jié)點(diǎn)也落入鎖住的部分區(qū)間八回,所以會(huì)被阻塞住。
UPDATE z SET id = 6 WHERE id = 8;

本文是作者根據(jù)日常業(yè)務(wù)場(chǎng)景驾诈,寫(xiě)出的一些解決問(wèn)題或?qū)嵤┫敕ǖ臍v程缠诅。如有錯(cuò)誤的地方,還請(qǐng)指出乍迄,相互學(xué)習(xí)管引,共同進(jìn)步。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末闯两,一起剝皮案震驚了整個(gè)濱河市褥伴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌漾狼,老刑警劉巖重慢,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異逊躁,居然都是意外死亡似踱,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門稽煤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)核芽,“玉大人,你說(shuō)我怎么就攤上這事酵熙≡颍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵匾二,是天一觀的道長(zhǎng)哮独。 經(jīng)常有香客問(wèn)我庐橙,道長(zhǎng),這世上最難降的妖魔是什么借嗽? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任态鳖,我火速辦了婚禮,結(jié)果婚禮上恶导,老公的妹妹穿的比我還像新娘浆竭。我一直安慰自己,他們只是感情好惨寿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布邦泄。 她就那樣靜靜地躺著,像睡著了一般裂垦。 火紅的嫁衣襯著肌膚如雪顺囊。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,274評(píng)論 1 300
  • 那天蕉拢,我揣著相機(jī)與錄音特碳,去河邊找鬼。 笑死晕换,一個(gè)胖子當(dāng)著我的面吹牛午乓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闸准,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼益愈,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了夷家?” 一聲冷哼從身側(cè)響起蒸其,我...
    開(kāi)封第一講書(shū)人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎库快,沒(méi)想到半個(gè)月后摸袁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缺谴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年但惶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片湿蛔。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膀曾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出阳啥,到底是詐尸還是另有隱情添谊,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布察迟,位于F島的核電站斩狱,受9級(jí)特大地震影響耳高,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜所踊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一泌枪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秕岛,春花似錦碌燕、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至遏考,卻和暖如春慈鸠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背灌具。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工青团, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人稽亏。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓壶冒,卻偏偏與公主長(zhǎng)得像缕题,于是被迫代替她去往敵國(guó)和親截歉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容