MySQL InnoDB支持三種行鎖定方式:
堅(jiān)守“ 做人真誠 · 做事靠譜 · 口碑至上 · 高效敬業(yè) ”的價(jià)值觀,專業(yè)網(wǎng)站建設(shè)服務(wù)10余年為成都木托盤小微創(chuàng)業(yè)公司專業(yè)提供企業(yè)網(wǎng)站建設(shè)營銷網(wǎng)站建設(shè)商城網(wǎng)站建設(shè)手機(jī)網(wǎng)站建設(shè)小程序網(wǎng)站建設(shè)網(wǎng)站改版,從內(nèi)容策劃、視覺設(shè)計(jì)、底層架構(gòu)、網(wǎng)頁布局、功能開發(fā)迭代于一體的高端網(wǎng)站建設(shè)服務(wù)。
行鎖(Record Lock):鎖直接加在索引記錄上面。
間隙鎖(Gap Lock):鎖加在不存在的空閑空間,可以是兩個(gè)索引記錄之間,也可能是第一個(gè)索引記錄之前或最后一個(gè)索引之后的空間。
Next-Key Lock:行鎖與間隙鎖組合起來用就叫做Next-Key Lock。
默認(rèn)情況下,InnoDB工作在可重復(fù)讀隔離級(jí)別下,并且以Next-Key Lock的方式對(duì)數(shù)據(jù)行進(jìn)行加鎖,這樣可以有效防止幻讀的發(fā)生。Next-Key Lock是行鎖與間隙鎖的組合,這樣,當(dāng)InnoDB掃描索引記錄的時(shí)候,會(huì)首先對(duì)選中的索引記錄加上行鎖(Record Lock),再對(duì)索引記錄兩邊的間隙(向左掃描掃到第一個(gè)比給定參數(shù)小的值, 向右掃描掃描到第一個(gè)比給定參數(shù)大的值, 然后以此為界,構(gòu)建一個(gè)區(qū)間)加上間隙鎖(Gap Lock)。如果一個(gè)間隙被事務(wù)T1加了鎖,其它事務(wù)是不能在這個(gè)間隙插入記錄的。
舉個(gè)例子:
表task_queue
Id taskId
1 2
3 9
10 20
40 41
開啟一個(gè)會(huì)話: session 1
sql> set autocommit=0;
##
取消自動(dòng)提交
sql> delete from task_queue where taskId = 20;
sql> insert into task_queue values(20, 20);
在開啟一個(gè)會(huì)話: session 2
sql> set autocommit=0;
##
取消自動(dòng)提交
sql> delete from task_queue where taskId = 25;
sql> insert into task_queue values(30, 25);
在沒有并發(fā),或是極少并發(fā)的情況下, 這樣會(huì)可能會(huì)正常執(zhí)行,在Mysql中, 事務(wù)最終都是穿行執(zhí)行, 但是在高并發(fā)的情況下, 執(zhí)行的順序就極有可能發(fā)生改變, 變成下面這個(gè)樣子:
sql> delete from task_queue where taskId = 20;
sql> delete from task_queue where taskId = 25;
sql> insert into task_queue values(20, 20);
sql> insert into task_queue values(30, 25);
這個(gè)時(shí)候最后一條語句:insert into task_queue values(30, 25); 執(zhí)行時(shí)就會(huì)爆出死鎖錯(cuò)誤。因?yàn)閯h除taskId = 20這條記錄的時(shí)候,20 -- 41 都被鎖住了, 他們都取得了這一個(gè)數(shù)據(jù)段的共享鎖, 所以在獲取這個(gè)數(shù)據(jù)段的排它鎖時(shí)出現(xiàn)死鎖。
間隙鎖在InnoDB的唯一作用就是防止其它事務(wù)的插入操作,以此來達(dá)到防止幻讀的發(fā)生,所以間隙鎖不分什么共享鎖與排它鎖。另外,在上面的例子中,我們選擇的是一個(gè)普通(非唯一)索引字段來測(cè)試的,這不是隨便選的,因?yàn)槿绻鸌nnoDB掃描的是一個(gè)主鍵、或是一個(gè)唯一索引的話,那InnoDB只會(huì)采用行鎖方式來加鎖,而不會(huì)使用Next-Key Lock的方式,也就是說不會(huì)對(duì)索引之間的間隙加鎖,仔細(xì)想想的話,這個(gè)并不難理解,大家也可以自己測(cè)試一下。
要禁止間隙鎖的話,可以把隔離級(jí)別降為讀已提交,或者開啟參數(shù)innodb_locks_unsafe_for_binlog。