幻讀產(chǎn)生原因及解決方法
因?yàn)樾墟i只能鎖住行,但是新插入記錄這個(gè)動(dòng)作,要更新的是記錄之間的“間隙”。為了解決幻讀問(wèn)題,InnoDB 只好引入新的鎖,也就是間隙鎖 (Gap Lock)。
什么是間隙鎖
間隙鎖,鎖的就是兩個(gè)值之間的空隙,不允許兩個(gè)值之間再插一個(gè)值。
比如初始化插入了 6 個(gè)記錄,這就產(chǎn)生了 7 個(gè)間隙。分別是 (-∞,0)、(0,5)、(5,10)、(10,15)、(15,20)、(20, 25)、(25, +supremum),間隙鎖都是開(kāi)區(qū)間

image.png
和行鎖不一樣的是,跟間隙鎖存在沖突關(guān)系的,是“往這個(gè)間隙中插入一個(gè)記錄”這個(gè)操作。間隙鎖之間都不存在沖突關(guān)系。
缺點(diǎn):可能會(huì)導(dǎo)致同樣的語(yǔ)句鎖住更大的范圍,影響了并發(fā)度。
什么是next-key lock
間隙鎖和行鎖合稱 next-key lock,每個(gè) next-key lock 是前開(kāi)后閉區(qū)間。如果用 select * from t for update 要把整個(gè)表所有記錄鎖起來(lái),就形成了 7 個(gè) next-key lock,分別是 (-∞,0]、(0,5]、(5,10]、(10,15]、(15,20]、(20, 25]、(25, +supremum]。
和間隙鎖的最大區(qū)別是,next-key lock 為前開(kāi)后閉區(qū)間,這樣所有的next-key lock就可以把所有記錄鎖起來(lái)。
間隙鎖的加鎖規(guī)則
加鎖規(guī)則里面,包含了兩個(gè)“原則”、兩個(gè)“優(yōu)化”和一個(gè)“bug”
- 原則 1:加鎖的基本單位是 next-key lock。希望你還記得,next-key lock 是前開(kāi)后閉區(qū)間。
- 原則 2:查找過(guò)程中訪問(wèn)到的對(duì)象才會(huì)加鎖。
- 優(yōu)化 1:索引上的等值查詢,給唯一索引加鎖的時(shí)候,next-key lock 退化為行鎖。
- 優(yōu)化 2:索引上的等值查詢,向右遍歷時(shí)且最后一個(gè)值不滿足等值條件的時(shí)候,next-key lock 退化為間隙鎖。
- 一個(gè) bug:唯一索引上的范圍查詢會(huì)訪問(wèn)到不滿足條件的第一個(gè)值為止