以下**皆是針對資料庫預設的隔離級別(repeatable read)來說的
原則 1:加鎖的基本單位是 next-key lock。並且,next-key lock 是前開後閉區間。
原則 2:查詢過程中訪問到的物件才會加鎖。
優化1:索引上的等值查詢,給唯一索引加鎖的時候,next-key lock退化為行鎖。
優化2:索引上的等值查詢,向右遍歷時且最後乙個值不滿足等值條件的時候,next-key lock 退化為間隙鎖。
gap 鎖:命中的索引維度
記錄鎖:鎖定主鍵id
next-key: 命中的索引維度 + 鎖定主鍵id
在進行下列案例進行分析的過程中,請務必遵循上述兩個原則和兩個優化
資料準備:
建立資料庫表:
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);
案例1:
update t set d = d+ 1 where id = 7;
案例2:
select * from t where id >= 10 and id < 11 for update;
案例3:
select id from t where c = 5 lock in share mode;
案例4:
select * from t where c >= 10 and c < 11 for update;
案例5:
select * from t where c >= 15 and c <= 20 order by c desc lock in share mode;
案例6:
delete from t where c = 10 limit 2;
針對上述三個案例,分別分析案例中的sql語句的加鎖範圍;
update t set d = d+ 1 where id = 7;
1 首先根據主鍵索引找到id=7的記錄,並根據next-key演算法,鎖定的範圍是(5,10],根據 【優化2:索引上的等值查詢,向右遍歷時且最後乙個值不滿足等值條件的時候,next-key lock 退化為間隙鎖,此時的鎖定範圍應該是(5,10)。
綜上分析:鎖定範圍是id∈(5,10),如果想插入執行insert into t select 8,8,8; 是會被阻塞住的,如果插入update t set d = d + 1 where id= 10;是不會被阻塞的。
select * from t where id >= 10 and id < 11 for update;
1 首先根據主鍵索引,找到id=10的行,然後根據next-key演算法,鎖定範圍應該是(5,10], 根據【優化1:索引上的等值查詢,給唯一索引加鎖的時候,next-key lock退化為行鎖】,所以退化為行鎖。
2 表繼續向右掃瞄,範圍查詢到id=15結束掃瞄。根據【原則2:查詢過程中訪問到的物件才會加鎖】,所以因此next-key的範圍是(10,15]
綜上分析,鎖定的範圍是id∈[10,15]
select id from t where c = 5 lock in share mode;
1 首先根據索引c找到c=5的記錄,根據lock-key演算法,鎖定的範圍應該是(0,5]
2 但是因為5是非唯一索引,所以當訪問到c=5記錄時,並不會立馬停止下來,繼續向右掃瞄,直到找到c=10才能停下來,根據【原則 2:查詢過程中訪問到的物件才會加鎖】,所以這裡會加(5,10]的next-key鎖。
3 同時掃瞄到c=10的記錄時,同時滿足了【優化2:索引上的等值查詢,向右遍歷時且最後乙個值不滿足等值條件的時候,next-key lock 退化為間隙鎖。】,所以(5,10]退化為(5,10)。
4 因為這裡使用了覆蓋索引,並沒有用到主鍵索引,所以主鍵上並沒有任何索引。
綜上,鎖定的範圍為c∈(0,10)。
select * from t where c >= 10 and c < 11 for update;
1 首先根據索引找到第乙個c=10的記錄,然後向右掃瞄。當找到c=10的記錄時,加next-key,鎖定範圍是(5,10]
2 繼續向右,找到c=15的記錄,此時不滿足c<11,掃瞄結束,加next-key為(10,15];
3 因為用到了for update,mysql會預設接下在會執行更新操作,所以會在id=15的索引上加上記錄鎖。
綜上,鎖定的範圍是c∈(5,15],id=15的記錄鎖
select * from t where c >= 15 and c <= 20 order by c desc lock in share mode;
1 因為order by c desc ,導致mysql從右向左進行匹配。
2 首先找到c=20最右側值——先找到c=20的最左側值,找到後加next-key(15,20],然後向右掃瞄,找到第乙個不等於20的記錄,即c=25,加上next-key (20,25],因為滿足優化2,最後乙個值不滿足等值條件,會退化為間隙鎖,即(20,25)。
所以此時的鎖為next-key(20,25),(15,20]。
3 再定位c=15的記錄,找到c=15後,要掃瞄到c=10才會停下來,所以加上next-key(5,10]和next-key(10,15],因為優化2,所以next-key退化為(10,15)
4 因為使用的是in share mode;,所以主鍵上不會加索引;
綜上,加鎖情況為:(5,10],(10,15],(15,20],(20,25);
在表中新增insert into t select 11,10,11;
表中資料現在為:
delete from t where c = 10 limit 2;
如果沒有limit欄位,則加鎖情況應該是(5,10],(10,15)
但是現在有了limit 2,資料庫表中也有兩條c=10的記錄,因此在遍歷到了c=10時,有兩條記錄已經滿足了,迴圈就結束了,就不需要後邊的(10,15)的鎖了。
本文圍繞著加鎖規則和鎖優化分析了6個鎖的案例,分別從唯一索引等值鎖、唯一索引非等值鎖、非唯一索引等值鎖、非唯一索引非等值鎖,以及非等值鎖的倒敘掃瞄加鎖規則和乙個limit的鎖優化等方面來分析鎖的情況。
mysql鎖機制總結 mysql鎖機制總結
1.隔離級別 1 讀不提交 read uncommited,ru 這種隔離級別下,事務間完全不隔離,會產生髒讀,可以讀取未提交的記錄,實際情況下不會使用。2 讀提交 read commited,rc 僅能讀取到已提交的記錄,這種隔離級別下,會存在幻讀現象,所謂幻讀是指在同乙個事務中,多次執行同乙個查...
mysql鎖機制 mysql 鎖機制
一 概述 mysql有三種鎖的級別 頁級 表級 行級。myisam和memory儲存引擎採用的是表級鎖 table level locking bdb儲存引擎採用的是頁面鎖 page level locking 但也支援表級鎖 innodb儲存引擎既支援行級鎖 row level locking 也...
mysql鎖機制 php Mysql鎖機制
表級鎖 開銷小,加鎖快 不會出現死鎖 鎖定粒度大,發生鎖衝突的概率最高,併發度最低。行級鎖 開銷大,加鎖慢 會出現死鎖 鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。共享鎖和排它鎖 頁面鎖 開銷和加鎖時間界於表鎖和行鎖之間 會出現死鎖 鎖定粒度界於表鎖和行鎖之間,併發度一般 mysql的行級鎖有...