1.在可重複讀隔離級別下,普通的查詢是快照讀,是不會看到別的事務插入的資料的。因此,幻讀在「當前讀」下才會出現。
2.幻讀指新插入的行,讀到原本存在行的更新結果不算。因為當前讀的作用就是能讀到所有已經提交記錄的最新值。
產生幻讀的原因是,行鎖只能鎖住行,但是新插入記錄這個動作,要更新的是記錄之間的「間隙」。因此,為了解決幻讀問題,innodb只好引入新的鎖,也就是間隙鎖(gap lock)。 間隙鎖在可重複讀隔離級別下才有效。
行鎖,分成讀鎖和寫鎖。兩種型別行鎖的衝突關係。
間隙鎖,鎖的就是兩個值之間的空隙。 間隙鎖和行鎖合稱next-key lock,每個next-key lock是前開後閉區間。
間隙鎖存在衝突關係的,是「往這個間隙中插入乙個記錄」這個操作。間隙鎖之間都不存在衝突關係。
兩個「原則」、兩個「優化」和乙個「bug」:
1.加鎖的基本單位是next-key lock,next-key lock是前開後閉區間。
2.查詢過程中訪問到的物件才會加鎖。
3.索引上的等值查詢,給唯一索引加鎖的時候,next-key lock退化為行鎖。
4.索引上的等值查詢,向右遍歷時且最後乙個值不滿足等值條件的時候,next-key lock退化為間隙鎖。
5.唯一索引上的範圍查詢會訪問到不滿足條件的第乙個值為止。
create tablet
(
id
int(11) not null,
c
int(11) default null,
d
int(11) default null,
primary key (id
),
keyc
(c
)
) engine=innodb;
insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);
兩個session來模擬併發,並假設n=9。
執行順序:
1session a 執行select … for update語句,由於id=9這一行並不存在,因此會加上間隙鎖(5,10);
2.session b 執行select … for update語句,同樣會加上間隙鎖(5,10),間隙鎖之間不會衝突,因此這個語句可以執行成功;
3.session b 試圖插入一行(9,9,9),被session a的間隙鎖擋住了,只好進入等待;
4.session a試圖插入一行(9,9,9),被session b的間隙鎖擋住了。
至此,兩個session進入互相等待狀態,形成死鎖。當然,innodb的死鎖檢測馬上就發現了這對死鎖關係,讓session a的insert語句報錯返回了。
間隙鎖的引入,可能會導致同樣的語句鎖住更大的範圍,這其實是影響了併發度的。
[資料**]
1.mysql實戰45講-丁奇
mysql MVCC 間隙鎖解決幻讀理解
mysql的隔離級別?讀未提交 讀提交 可重複讀 序列化 innodb預設級別為可重複讀,可重複讀會產生問題 就是幻讀。什麼是幻讀?不可重複讀側重於update這種操作,同一條資料前後讀起來不一樣的情況,幻讀側重於insert delete這種操作,前後兩次select 資料的數量會發生變化 舉個例...
mysql筆記系列 十八 幻讀和間隙鎖
幻讀指的是乙個事務在前後兩次查詢同乙個範圍的時候,後一次查詢看到了前一次查詢沒有看到的行。在可重複讀隔離級別下,普通的查詢是快照讀 使用事務版本確定了資料的可見性 是不會看到別的事務插入的資料的。因此,幻讀在 當前讀 下才會出現 select from where c 5 for update 這種...
mysql間隙鎖 mysql間隙鎖
前面一文 mysql鎖 介紹了mysql innodb儲存引擎的各種鎖,本文介紹一下innodb儲存引擎的間隙鎖,就以下問題展開討論 1.什麼是間隙鎖?間隙鎖是怎樣產生的?2.間隙鎖有什麼作用?3.使用間隙鎖有什麼隱患?一 間隙鎖的基本概念 1.什麼叫間隙鎖 當我們用範圍條件而不是相等條件檢索資料,...