概念
行級鎖就是鎖住表中指定行的記錄卿叽。
行鎖原理
InnoDB行鎖是通過給索引項加鎖來實現(xiàn)的肝集,如果沒有建立索引恰聘,那么采用表默認的隱式主鍵來鎖定魂挂。
innodb引擎提供行鎖種類
- Record Lock:單個行記錄上加鎖。鎖定的是索引項慧邮,如果沒有設置索引调限,將使用隱式的主鍵鎖定寞宫。
- Gap Lock:間隙鎖篮愉,不包含本身記錄的鎖定范圍。
-
Next-Key Lock:Record Lock+Gap Lock炎码。鎖定范圍且包含自身記錄忆谓。
InnoDB默認存儲引擎是REPEATABLE READ模式裆装,Next-Key Lock算法是默認的行記錄算法。
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
行鎖的實現(xiàn)方式
共享鎖陪毡、排他鎖
Record Lock(單條記錄鎖)
- 鎖定范圍:當前單條記錄米母。
session1 | session2 |
---|---|
set autocommit = 0; | set autocommit = 0; |
select * from edu_user where id = "5045dfba5f5b4cb5b805c379fc538bcb" for update; | |
成功:select * from edu_user; | |
成功:select * from edu_user where id = "1234df4446cb4cb6bc2f639830b12345" for update; | |
阻塞:select * from edu_user where id = "5045dfba5f5b4cb5b805c379fc538bcb" for update; | |
commit; | |
執(zhí)行阻塞內(nèi)容 | |
commit; |
說明:鎖住了id為5045dfba5f5b4cb5b805c379fc538bcb的記錄,其他行記錄可以查詢毡琉,也可以鎖操作、讀寫妙色。
Next-Key Lock(范圍鎖)
- 設計范圍鎖的目的:解決幻讀問題(Phantom Problem)桅滋。
- 什么是幻讀:就是在同一事務中,連續(xù)執(zhí)行兩次同樣的sql語句出現(xiàn)不同結(jié)果,第二次sql語句可能會返回之前不存在的行丐谋。
- 正常鎖定范圍:[prev_val芍碧,where_val)、[where_val号俐,post_val)泌豆。
- 范圍鎖防止幻讀:當前會話A會鎖定值的前面區(qū)域和后面區(qū)域,防止在操作過程中吏饿,會話B插入了值踪危,造成會話C讀取兩次結(jié)果不同。
操作:
session1 | session2 |
---|---|
set autocommit = 0; | set autocommit = 0; |
select * from edu_test where a_val = '11' for update; | |
成功:insert into edu_test select 6, '9', '9'; | |
成功:insert into edu_test select 7, '14', '14'; | |
成功:insert into edu_test select 9, '13', '13'; | |
阻塞:insert into edu_test select 10, '12', '12'; | |
阻塞:insert into edu_test select 11, '11', '11'; | |
阻塞:insert into edu_test select 12, '10', '10'; | |
commit | |
commit; | |
執(zhí)行阻塞內(nèi)容 |
說明:a_val非主鍵值設置了索引猪落,a_val值為11上排他鎖贞远,那么鎖定的范圍應該為[10,11)笨忌、[11,13)蓝仲。
Next-Key Lock 退化為 Record Lock
- 結(jié)論:當查詢的索引含有唯一屬性時,innodb會對Next-Key Lock優(yōu)化官疲,將其降級為Record Lock袱结,即鎖住索引本身,而不是范圍途凫。
- 鎖定范圍:當前單條唯一記錄垢夹。
操作:
session1 | session2 |
---|---|
set autocommit = 0; | set autocommit = 0; |
select * from edu_test where a_val = '11' for update; | |
成功:insert into edu_test select 6, '12', '12'; | |
commit; | |
commit |
說明:a_val非主鍵值設置為唯一索引,a_val值為11上了排他鎖颖榜,那么鎖定只為a_val=11的記錄棚饵,其他記錄不鎖定,當前鎖已經(jīng)退化為了單條記錄鎖掩完,如果硬插入a_val=11的記錄噪漾,那么只會報值重復錯誤,鎖粒度減小且蓬,提高了并發(fā)性欣硼。
Next-Key Lock 退化為 Gap Lock
- 結(jié)論:當查詢的索引的值不存在時,那么innodb會對Next-Key Lock優(yōu)化恶阴,將其退化為Gap Lock诈胜。
- 鎖定范圍:[prev_val,post_val)冯事。
操作:
session1 | session2 |
---|---|
set autocommit = 0; | set autocommit = 0; |
select * from edu_test where a_val = '12' for update; | |
成功:insert into edu_test select 6, 9, '9'; | |
成功:insert into edu_test select 7, 10, '10'; | |
成功:insert into edu_test select 8, 14, '14'; | |
成功:insert into edu_test select 9, 13, '13'; | |
阻塞:insert into edu_test select 10, 11, '11'; | |
阻塞:insert into edu_test select 11, 12, '12'; | |
commit | |
commit; | |
執(zhí)行阻塞內(nèi)容 |
說明:a_val非主鍵值設置了索引焦匈,a_val設置了不存在的排他鎖,這樣innodb會對Next-Key Lock優(yōu)化昵仅,將其退化為Gap Lock缓熟。鎖定范圍是[11, 13)累魔。
order by 排序情況
order by排序會先將當前需要查詢的結(jié)果排序,然后根據(jù)查詢索引值前后加鎖够滑。
- 鎖定范圍:(prev_val垦写,post_val]。
操作:
session1 | session2 |
---|---|
set autocommit = 0; | set autocommit = 0; |
select * from edu_test where a_val = 20 order by a_val desc for update; | |
成功:insert into edu_test select 6, 12, '12'; | |
成功:insert into edu_test select 7, 32, '32'; | |
成功:insert into edu_test select 8, 31, '31'; | |
阻塞:insert into edu_test select 9, 13, '13'; | |
阻塞:insert into edu_test select 10, 25, '25'; | |
commit | |
commit; | |
執(zhí)行阻塞內(nèi)容 |
分析:先倒序排序
31彰触, 20梯投, 13, 11况毅, 10
說明:當前索引值a_val為20分蓖,那么鎖定范圍為(31,13]俭茧。
范圍查詢情況
- 鎖定范圍:(prev_val咆疗,val1]、(val1母债,val2]午磁、(val2,post_val]毡们。
操作:
session1 | session2 |
---|---|
set autocommit = 0; | set autocommit = 0; |
select * from edu_test where a_val < 20 and a_val > 11 order by a_val desc for update; | |
成功:insert into edu_test select 6, 31, '31'; | |
阻塞:insert into edu_test select 7, 10, '10'; | |
commit | |
commit; | |
執(zhí)行阻塞內(nèi)容 |
分析:先倒序排序
31迅皇, 20, 13衙熔, 11登颓, 10
說明:當前索引值a_val為小于20、大于11红氯,那么鎖定范圍為(31框咙,10]。
參考
《MySQL技術(shù)內(nèi)幕》InnoDB存儲引擎