因為行鎖只能鎖住行,但是新插入記錄這個動作,要更新的是記錄之間的“間隙”。為了解決幻讀問題,InnoDB 只好引入新的鎖,也就是間隙鎖 (Gap Lock)。
目前成都創(chuàng)新互聯(lián)已為1000多家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)頁空間、網(wǎng)站托管維護、企業(yè)網(wǎng)站設(shè)計、陽泉網(wǎng)站維護等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
間隙鎖,鎖的就是兩個值之間的空隙,不允許兩個值之間再插一個值。
比如初始化插入了 6 個記錄,這就產(chǎn)生了 7 個間隙。分別是 (-∞,0)、(0,5)、(5,10)、(10,15)、(15,20)、(20, 25)、(25, +supremum),間隙鎖都是開區(qū)間
和行鎖不一樣的是,跟間隙鎖存在沖突關(guān)系的,是“往這個間隙中插入一個記錄”這個操作。間隙鎖之間都不存在沖突關(guān)系。
缺點:可能會導(dǎo)致同樣的語句鎖住更大的范圍,影響了并發(fā)度。
間隙鎖和行鎖合稱 next-key lock,每個 next-key lock 是前開后閉區(qū)間。如果用 select * from t for update 要把整個表所有記錄鎖起來,就形成了 7 個 next-key lock,分別是 (-∞,0]、(0,5]、(5,10]、(10,15]、(15,20]、(20, 25]、(25, +supremum]。
和間隙鎖的最大區(qū)別是,next-key lock 為前開后閉區(qū)間,這樣所有的next-key lock就可以把所有記錄鎖起來。
加鎖規(guī)則里面,包含了兩個“原則”、兩個“優(yōu)化”和一個“bug”
意向鎖(Intention Locks; table-level lock)
意向鎖是一種特殊的表級鎖,意向鎖是為了讓 InnoDB 多粒度的鎖能共存而設(shè)計的。取得行的共享鎖和排他鎖之前需要先取得表的意向共享鎖(IS)和意向排他鎖(IX),意向共享鎖和意向排他鎖都是系統(tǒng)自動添加和自動釋放的,整個過程無需人工干預(yù)
意向鎖就是指未來的某一個時刻事務(wù)可能要加共享鎖或者排它鎖,提前聲明一個意向,分為兩種:
意向共享鎖(Intention Shared Lock) IS
事務(wù)有意向?qū)Ρ碇械哪承┬屑庸蚕礞i(S鎖)
意向排它鎖(Intention Exclusive Lock)IX
事務(wù)有意向?qū)Ρ碇械哪承┬屑优潘i(X鎖)
記錄鎖(Record Locks)
官方原文
SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE; 這一行則是使用了記錄鎖,不允許其他事務(wù)進行增,刪,改
但是 SELECT c1 FROM t WHERE c1 = 10; 是沒有鎖的,走的是快照讀,上文已經(jīng)闡明過了
記錄鎖本身不是鎖定記錄數(shù)據(jù)本身而是鎖定索引記錄,如果要鎖的列沒有索引,則會進行全表記錄加鎖
間隙鎖(Gap Locks)
官方原文
比如 SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE ;
插入 c1 為 15 的記錄會被鎖定不可執(zhí)行
這種默認存在于可重復(fù)讀的事務(wù)隔離級別中的鎖,鎖定被圈定的范圍不允許 insert,防止不可重復(fù)讀,上文說了我們的事務(wù)隔離級別都是讀已提交,默認會產(chǎn)生不可重復(fù)讀的問題
mysql 為并發(fā)事務(wù)同時對一條記錄進行讀寫時,提出了兩種解決方案:
1)使用 mvcc 的方法,實現(xiàn)多事務(wù)的并發(fā)讀寫,但是這種讀只是“快照讀”,一般讀的是歷史版本數(shù)據(jù),還有一種是“當前讀”,一般加鎖實現(xiàn)“當前讀”,或者 insert、update、delete 也是當前讀。
2)使用加鎖的方法,鎖分為共享鎖(讀鎖),排他鎖(寫鎖)
快照讀:就是select
當前讀:特殊的讀操作,插入/更新/刪除操作,屬于當前讀,處理的都是當前的數(shù)據(jù),需要加鎖。
mysql 在 RR 級別怎么處理幻讀的呢?一般來說,RR 級別通過 mvcc 機制,保證讀到低于后面事務(wù)的數(shù)據(jù)。但是 select for update 不會觸發(fā) mvcc,它是當前讀。如果后面事務(wù)插入數(shù)據(jù)并提交,那么在 RR 級別就會讀到插入的數(shù)據(jù)。所以,mysql 使用 行鎖 + gap 鎖(簡稱 next-key 鎖)來防止當前讀的時候插入。
Gap Lock在InnoDB的唯一作用就是防止其他事務(wù)的插入操作,以此防止幻讀的發(fā)生。
Innodb自動使用間隙鎖的條件: