MySQL知識點(diǎn)之InnoDB中的行級鎖是什么

今天小編給大家分享一下MySQL知識點(diǎn)之InnoDB中的行級鎖是什么的相關(guān)知識點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

成都創(chuàng)新互聯(lián)致力于成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì),成都網(wǎng)站設(shè)計(jì),集團(tuán)網(wǎng)站建設(shè)等服務(wù)標(biāo)準(zhǔn)化,推過標(biāo)準(zhǔn)化降低中小企業(yè)的建站的成本,并持續(xù)提升建站的定制化服務(wù)水平進(jìn)行質(zhì)量交付,讓企業(yè)網(wǎng)站從市場競爭中脫穎而出。 選擇成都創(chuàng)新互聯(lián),就選擇了安全、穩(wěn)定、美觀的網(wǎng)站建設(shè)服務(wù)!

MySQL知識點(diǎn)之InnoDB中的行級鎖是什么

行鎖,也稱為記錄鎖,顧名思義就是在記錄上加的鎖。但是要注意,這個記錄指的是通過給索引上的索引項(xiàng)加鎖。InnoDB 這種行鎖實(shí)現(xiàn)特點(diǎn)意味著:只有通過索引條件檢索數(shù)據(jù),InnoDB才使用行級鎖,否則,InnoDB將使用表鎖。

不論是使用主鍵索引、唯一索引或普通索引,InnoDB都會使用行鎖來對數(shù)據(jù)加鎖。

只有執(zhí)行計(jì)劃真正使用了索引,才能使用行鎖:即便在條件中使用了索引字段,但是否使用索引來檢索數(shù)據(jù)是由MySQL 通過判斷不同執(zhí)行計(jì)劃的代價(jià)來決定的,如果MySQL認(rèn)為全表掃描效率更高,比如對一些很小的表,它就不會使用索引,這種情況下InnoDB將使用表鎖,而不是行鎖。

同時(shí)當(dāng)我們用范圍條件而不是相等條件檢索數(shù)據(jù),并請求鎖時(shí),InnoDB會給符合條件的已有數(shù)據(jù)記錄的索引項(xiàng)加鎖。

不過即使是行鎖,InnoDB里也是分成了各種類型的。換句話說即使對同一條記錄加行鎖,如果類型不同,起到的功效也是不同的。

這里我們還是使用前面的teacher表,增加一個索引,并插入幾條記錄。

mysql> desc teacher;
+--------+--------------+------+-----+---------+-------+
| Field  | Type         | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| number | int(11)      | NO   | PRI | NULL    |       |
| name   | varchar(100) | YES  | MUL | NULL    |       |
| domain | varchar(100) | YES  |     | NULL    |       |
+--------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

mysql> select * from teacher;
+--------+------+--------+
| number | name | domain |
+--------+------+--------+
|      1 | T    | Java   |
|      3 | M    | redis  |
|      9 | X    | MQ     |
|     15 | O    | Python |
|     21 | A    | Golang |
+--------+------+--------+
5 rows in set (0.00 sec)

我們來看看都有哪些常用的行鎖類型。

Record Locks

也叫記錄鎖,就是僅僅把一條記錄鎖上,官方的類型名稱為:LOCK_REC_NOT_GAP。比方說我們把number值為9的那條記錄加一個記錄鎖的示意圖如下:

MySQL知識點(diǎn)之InnoDB中的行級鎖是什么

記錄鎖是有S鎖和X鎖之分的,當(dāng)一個事務(wù)獲取了一條記錄的S型記錄鎖后,其他事務(wù)也可以繼續(xù)獲取該記錄的S型記錄鎖,但不可以繼續(xù)獲取X型記錄鎖;當(dāng)一個事務(wù)獲取了一條記錄的X型記錄鎖后,其他事務(wù)既不可以繼續(xù)獲取該記錄的S型記錄鎖,也不可以繼續(xù)獲取X型記錄鎖。

T1T2
begin;
select * from teacher where number=9 for update;

select * from teacher where number=9 for update; # 阻塞

Gap Locks

MySQL在REPEATABLE READ隔離級別下是可以部分解決幻讀問題的,解決方案有兩種,可以使用MVCC方案解決,也可以采用加鎖方案解決。但是在使用加鎖方案解決時(shí)有問題,就是事務(wù)在第一次執(zhí)行讀取操作時(shí),那些幻影記錄尚不存在,我們無法給這些幻影記錄加上記錄鎖。InnoDB提出了一種稱之為Gap Locks的鎖,官方的類型名稱為:LOCK_GAP,我們也可以簡稱為gap鎖。

間隙鎖實(shí)質(zhì)上是對索引前后的間隙上鎖,不對索引本身上鎖。

T1T2
begin;
update teacher set domain=‘Redis’ where name=‘M’;

insert into teacher value(23,‘B’,‘docker’); # 阻塞

insert into teacher value(23,‘B’,‘docker’); # 阻塞

事務(wù)T1會對([A, 21], [M, 3])、([M, 3], [O, 15])之間進(jìn)行上gap鎖,如下圖中所示:

MySQL知識點(diǎn)之InnoDB中的行級鎖是什么

意味著不允許別的事務(wù)在這條記錄前后間隙插入新記錄,所以T2就不能插入。

但是當(dāng)SQL語句變?yōu)椋?/p>

insert into teacher value(70,'P','docker');

能插入嗎?當(dāng)然能,因?yàn)椋?0,‘P’)這條記錄不在被鎖的區(qū)間內(nèi)。

思考題

現(xiàn)在有表,表中有記錄如下:

list = ['su liang','hacker','ice']
list.insert(1,'kiko')
print(list)
#結(jié)果:['su liang', 'kiko', 'hacker', 'ice']

開啟一個事務(wù):

begin;SELECT * FROM test1 WHERE number = 3 FOR UPDATE;

開啟另外一個事務(wù):

INSERT INTO test1 (id, number) VALUES (2, 1); # 阻塞
INSERT INTO test1 (id, number) VALUES (3, 2); # 阻塞
INSERT INTO test1 (id, number) VALUES (6, 8); # 阻塞
INSERT INTO test1 (id, number) VALUES (8, 8); # 正常執(zhí)行
INSERT INTO test1 (id, number) VALUES (9, 9); # 正常執(zhí)行
INSERT INTO test1 (id, number) VALUES (10, 12); # 正常執(zhí)行
UPDATE test1 SET number = 5 WHERE id = 11 AND number = 12; # 阻塞

為什么(6,8)不能執(zhí)行,(8,8)可以執(zhí)行?這個間隙鎖的范圍應(yīng)該是[1,8],最后一個語句為什么不能執(zhí)行?
解決思路:畫一個number的索引數(shù)據(jù)存放的圖,然后根據(jù)間隙鎖的加鎖方式,把鎖加上,就能很快明白答案。

MySQL知識點(diǎn)之InnoDB中的行級鎖是什么

  1. 當(dāng)插入的number在(1,8)區(qū)間都會被阻塞

  2. 當(dāng)插入的number等于1、8,那么id在(1,4]、[6,7)區(qū)間會被阻塞

Next-Key Locks

有時(shí)候我們既想鎖住某條記錄,又想阻止其他事務(wù)在該記錄前邊的間隙插入新記錄,所以InnoDB就提出了一種稱之為Next-Key Locks的鎖,官方的類型名稱為:LOCK_ORDINARY,我們也可以簡稱為next-key鎖。next-key鎖的本質(zhì)就是
一個記錄鎖和一個gap鎖的合體。

默認(rèn)情況下,InnoDB以REPEATABLE READ隔離級別運(yùn)行。在這種情況下,InnoDB使用Next-Key Locks鎖進(jìn)行搜索和索引掃描,這可以防止幻讀的發(fā)生。

Insert Intention Locks

我們說一個事務(wù)在插入一條記錄時(shí)需要判斷一下插入位置是不是被別的事務(wù)加了所謂的gap鎖(next-key鎖也包含gap 鎖,后邊就不強(qiáng)調(diào)了),如果有的話,插入操作需要等待,直到擁有g(shù)ap鎖的那個事務(wù)提交。

但是InnoDB規(guī)定事務(wù)在等待的時(shí)候也需要在內(nèi)存中生成一個鎖結(jié)構(gòu),表明有事務(wù)想在某個間隙中插入新記錄,但是現(xiàn)在處于等待狀態(tài)。這種類型的鎖命名為Insert Intention Locks,官方的類型名稱為:LOCK_INSERT_INTENTION,我們也可以稱為插入意向鎖。

可以理解為插入意向鎖是一種鎖的的等待隊(duì)列,讓等鎖的事務(wù)在內(nèi)存中進(jìn)行排隊(duì)等待,當(dāng)持有鎖的事務(wù)完成后,處于等待狀態(tài)的事務(wù)就可以獲得鎖繼續(xù)事務(wù)了。

隱式鎖

鎖的的維護(hù)是需要成本的,為了節(jié)約資源,MySQL在設(shè)計(jì)提出了了一個隱式鎖的概念。一般情況下INSERT操作是不加鎖的,當(dāng)然真的有并發(fā)沖突的情況下下,還是會導(dǎo)致問題的。

所以MySQL中,一個事務(wù)對新插入的記錄可以不顯式的加鎖,但是別的事務(wù)在對這條記錄加S鎖或者X鎖時(shí),會去檢查索引記錄中的trx_id隱藏列,然后進(jìn)行各種判斷,會先幫助當(dāng)前事務(wù)生成一個鎖結(jié)構(gòu),然后自己再生成一個鎖結(jié)構(gòu)后進(jìn)入等待狀態(tài)。但是由于事務(wù)id的存在,相當(dāng)于加了一個隱式鎖。

這樣的話,隱式鎖就起到了延遲生成鎖的用處。這個過程,我們無法干預(yù),是由引擎自動處理的,對我們是完全透明的,我們知道下就行了。

鎖的內(nèi)存結(jié)構(gòu)

所謂的鎖其實(shí)是一個內(nèi)存中的結(jié)構(gòu),在事務(wù)執(zhí)行前本來是沒有鎖的,也就是說一開始是沒有鎖結(jié)構(gòu)和記錄進(jìn)行關(guān)聯(lián)的,當(dāng)一個事務(wù)想對這條記錄做改動時(shí),首先會看看內(nèi)存中有沒有與這條記錄關(guān)聯(lián)的鎖結(jié)構(gòu),當(dāng)沒有的時(shí)候就會在內(nèi)存中生成一個鎖結(jié)構(gòu)與之關(guān)聯(lián)。比方說事務(wù)T1要對記錄做改動,就需要生成一個鎖結(jié)構(gòu)與之關(guān)聯(lián)。

鎖結(jié)構(gòu)里至少要有兩個比較重要的屬性:

  • trx 信息:代表這個鎖結(jié)構(gòu)是哪個事務(wù)生成的。

  • is_waiting:代表當(dāng)前事務(wù)是否在等待。

MySQL知識點(diǎn)之InnoDB中的行級鎖是什么

當(dāng)事務(wù)T1改動了條記錄后,就生成了一個鎖結(jié)構(gòu)與該記錄關(guān)聯(lián),因?yàn)橹皼]有別的事務(wù)為這條記錄加鎖,所以is_waiting 屬性就是false,我們把這個場景就稱之為獲取鎖成功,或者加鎖成功,然后就可以繼續(xù)執(zhí)行操作了。

在事務(wù)T1提交之前,另一個事務(wù)T2也想對該記錄做改動,那么先去看看有沒有鎖結(jié)構(gòu)與這條記錄關(guān)聯(lián),發(fā)現(xiàn)有一個鎖結(jié)構(gòu)與之關(guān)聯(lián)后,然后也生成了一個鎖結(jié)構(gòu)與這條記錄關(guān)聯(lián),不過鎖結(jié)構(gòu)的is_waiting屬性值為true,表示當(dāng)前事務(wù)需要等待,我們把這個場景就稱之為獲取鎖失敗,或者加鎖失敗,或者沒有成功的獲取到鎖。

在事務(wù)T1提交之后,就會把該事務(wù)生成的鎖結(jié)構(gòu)釋放掉,然后看看還有沒有別的事務(wù)在等待獲取鎖,發(fā)現(xiàn)了事務(wù)T2還在等待獲取鎖,所以把事務(wù)T2對應(yīng)的鎖結(jié)構(gòu)的is_waiting屬性設(shè)置為false,然后把該事務(wù)對應(yīng)的線程喚醒,讓它繼續(xù)執(zhí)行,此時(shí)事務(wù)T2就算獲取到鎖了。這種實(shí)現(xiàn)方式非常像并發(fā)編程里AQS的等待隊(duì)列。

對一條記錄加鎖的本質(zhì)就是在內(nèi)存中創(chuàng)建一個鎖結(jié)構(gòu)與之關(guān)聯(lián)。那么,一個事務(wù)對多條記錄加鎖時(shí),是不是就要創(chuàng)建多個鎖結(jié)構(gòu)呢?比如:

SELECT * FROM teacher LOCK IN SHARE MODE;

很顯然,這條語句需要為teacher表中的所有記錄進(jìn)行加鎖。那么,是不是需要為每條記錄都生成一個鎖結(jié)構(gòu)呢?其實(shí)理論上創(chuàng)建多個鎖結(jié)構(gòu)沒有問題,反而更容易理解。但是如果一個事務(wù)要獲取10,000條記錄的鎖,要生成10,000個這樣的結(jié)構(gòu),不管是執(zhí)行效率還是空間效率來說都是很不劃算的,所以實(shí)際上,并不是一個記錄一個鎖結(jié)構(gòu)。

當(dāng)然鎖結(jié)構(gòu)實(shí)際是很復(fù)雜的,我們大概了解下里面包含哪些元素。

  • 鎖所在的事務(wù)信息:無論是表級鎖還是行級鎖,一個鎖屬于一個事務(wù),這里記載著該鎖對應(yīng)的事務(wù)信息。

  • 索引信息:對于行級鎖來說,需要記錄一下加鎖的記錄屬于哪個索引。

  • 表鎖/行鎖信息:表級鎖結(jié)構(gòu)和行級鎖結(jié)構(gòu)在這個位置的內(nèi)容是不同的。具體表現(xiàn)為表級鎖記載著這是對哪個表加的鎖,還有其他的一些信息;而行級鎖記載了記錄所在的表空間、記錄所在的頁號、區(qū)分到底是為哪一條記錄加了鎖的數(shù)據(jù)結(jié)構(gòu)。

  • 鎖模式:鎖是IS,IX,S,X 中的哪一種。
    鎖類型:表鎖還是行鎖,行鎖的具體類型。

  • 其他:一些和鎖管理相關(guān)的數(shù)據(jù)結(jié)構(gòu),比如哈希表和鏈表等。

基本上來說,同一個事務(wù)里,同一個數(shù)據(jù)頁面,同一個加鎖類型的鎖會保存在一起。

以上就是“MySQL知識點(diǎn)之InnoDB中的行級鎖是什么”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

網(wǎng)站欄目:MySQL知識點(diǎn)之InnoDB中的行級鎖是什么
新聞來源:http://muchs.cn/article14/iejoge.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、微信公眾號、外貿(mào)建站動態(tài)網(wǎng)站、用戶體驗(yàn)服務(wù)器托管

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)