34.Mysql怎樣加鎖淺談01
1.前言
本小結屬於怎樣判斷innodb內部怎樣加鎖的,資料innodb的核心篇,也是非常重要的一節
2.加鎖的規則
兩個原則、兩個優化、一個bug --->這裡的預設隔離級別是:可重複讀隔離級別
- 原則1:加鎖的基本單位是next-key-lock,是前開後閉區間
- 原則2: 查詢過程中訪問到的物件才會加鎖
- 優化1: 索引上的等值查詢,給唯一索引加鎖的時候,next-key-lock退化為行鎖。
- 優化2: 索引上的等值查詢,向右遍歷時且最後一個值不滿足等值條件的時候,next-key lock退化為間隙鎖。
- 一個bug: 唯一索引上的範圍查詢會訪問到不滿足條件的第一個值為止。
3.案例
這裡先建立一個表
CREATE TABLE `t` ( `id` int(11) NOT NULL, `c` int(11) DEFAULT NULL, `d` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `c` (`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);
案例一:等值查詢間隙鎖
分析:
由於id=7用的是唯一索引(主鍵索引),且id=7是在id=5和id=10之間,因此根據原則1,加鎖規則是next-key lock,索引加鎖的區間是(5,10];
然後再根據優化2:索引上進行等值查詢時,向右遍歷時且最後一個值不滿足等值條件的時候,next-key lock退化為間隙鎖,因此此時索引加鎖區間是(5,10)
案例二:非唯一索引等值鎖
分析:
1.此時看到c是普通索引
2.根據原則1:加鎖的單位是next-key lock,因此此時加鎖區間是(0,5],又因此c是普通索引,所以還需要向右遍歷,查到c=10才放棄。因此根據原則2,訪問到的都要加鎖,因此需要給(5,10]
加上next-key lock
3.但是同時這個符合優化 2:等值判斷,向右遍歷,最後一個值不滿足 c=5 這個等值條件,因此退化成間隙鎖 (5,10),因此最終的加鎖區間是(0,5]和(5,10)
案例三:主鍵索引範圍鎖
分析:
1.開始執行的時候,要找到第一個id=10的行,因此本該是next-key lock(5,10].根據優化1,主鍵id上的等值條件,退化為行鎖,只加了id=10這一行的行鎖。
2.範圍查詢就往後繼續找,找到id=15這一行停下來,因此需要加next-key lock(10,15].
所以,session A這時候鎖的範圍就是主鍵索引上,行鎖id=10和next-key lock(10,15].這樣session B和session C的結果你就能理解了。
案例四:非唯一索引範圍鎖
分析:
1.注意此時的約束條件時c欄位
2.這次session A用欄位c來判斷,加鎖規則跟案例三唯一不同的是:在第一次用c=10定位記錄的時候,索引c上加了(5,10]這個next-key lock之後,由於索引c是非唯一索引,沒有優化規則,也就是說不會蛻變為行鎖,因此最終session A加的鎖是,索引c上的(5,10]和(10,15]這兩個next-key lock.
所以從結果上來看,session B要插入(8,8,8)的這個insert 語句時就被堵住了。
這裡需要掃描到c=15才停止掃描,是合理的,因為innodb要掃到c=15,才知道不需要繼續往後找了。