l S(shared locks) 共享鎖:允許擁有鎖的事務(wù)讀一行數(shù)據(jù)
創(chuàng)新互聯(lián)公司是一家專注于成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)與策劃設(shè)計(jì),都安網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)公司做網(wǎng)站,專注于網(wǎng)站建設(shè)10年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:都安等地區(qū)。都安做網(wǎng)站價(jià)格咨詢:13518219792
l X (exclusive locks) 排他鎖:允許有用鎖的事務(wù)更新或刪除一行數(shù)據(jù)
如果一個(gè)事務(wù)T1在行r擁有一個(gè)S共享鎖,從不同的事務(wù)T2請(qǐng)求鎖定行r,處理如下:
l 事務(wù)T2能立即獲得行r的S共享鎖,因此,T1和T2都在行r上持有S共享鎖
l 事務(wù)T2不能獲得行r的X排它鎖
如果一個(gè)事務(wù)T1在行r持有x排它鎖,其他事務(wù)T2無(wú)法獲得任何類型的鎖。
Innodb支持多粒度鎖定,這種鎖定允許事務(wù)在行級(jí)上的鎖和表級(jí)上的鎖同時(shí)存在。為了支持在不同粒度上進(jìn)行加鎖操作,innodb支持一種額外的鎖方式,稱為意向鎖(intention locks)。
Innodb意向鎖為表級(jí)別的鎖,設(shè)計(jì)的主要目的主要是為了在下一個(gè)事務(wù)中揭示下一行將被請(qǐng)求的鎖類型。
InnoDB中有2中類型的意向鎖:
?Intention shared(IS): TransactionTintends to setSlocks on individual rows in tablet.
事務(wù)T想對(duì)表t的某些行設(shè)置共享鎖
?Intention exclusive(IX): TransactionTintends to setXlocks on those rows.
事務(wù)T想對(duì)表t的某些行設(shè)置排它鎖
例如:SELECT ... LOCK IN SHARE MODE設(shè)置了一個(gè)IS鎖
SELECT ... FOR UPDATE設(shè)置一個(gè)IX鎖
意向鎖協(xié)議如下:
?一個(gè)事務(wù)在可以獲得表t的某些行的S共享鎖,必須先獲取表t的IS意向共享鎖
?一個(gè)事務(wù)在可以會(huì)的表t的某些行的X排它鎖,必須先獲取表t的IX意向排它鎖
Innodb鎖兼容性矩陣
意向鎖不會(huì)堵塞除了全表操作(例:LOCK TABLES ...WRITE)以外的任何請(qǐng)求,其意向鎖的主要目的是顯示某些操作鎖定了某行,或者將要鎖定某行。
意向鎖的存在價(jià)值在于在定位到特定的行所持有的鎖之前,提供一種更粗粒度的鎖,可以大大節(jié)約引擎對(duì)于鎖的定位和處理的性能,因?yàn)樵诖鎯?chǔ)引擎內(nèi)部,鎖是由一塊獨(dú)立的數(shù)據(jù)結(jié)構(gòu)維護(hù)的,鎖的數(shù)量直接決定了內(nèi)存的消耗和并發(fā)性能。例如,事務(wù)A對(duì)表t的某些行修改(DML通常會(huì)產(chǎn)生X鎖),需要對(duì)t加上意向排它鎖,在A事務(wù)完成之前,B事務(wù)來(lái)一個(gè)全表操作(alter table等),此時(shí)直接在表級(jí)別的意向排它鎖就能告訴B需要等待(因?yàn)閠上有意向鎖),而不需要再去行級(jí)別判斷
意向鎖實(shí)際上可以理解為一種“暗示”未來(lái)需要什么樣行級(jí)鎖:
IS表示未來(lái)可能需要在這個(gè)表的某些記錄上加共享鎖
IX表示未來(lái)可能需要在這個(gè)表的某些記錄上加排他鎖。
意向鎖是表級(jí)別的,IS和IX鎖之間相互并不沖突,但與表級(jí)S/X鎖沖突。
在對(duì)記錄加S鎖或者X鎖時(shí),必須保證其在相同的表上有對(duì)應(yīng)的意向鎖或者鎖強(qiáng)度更高的表級(jí)鎖
Innodb的行鎖的類型:
? Record lock:鎖定一個(gè)索引記錄
? Gap lock:鎖定一個(gè)范圍,不包含記錄本身
? Next-key lock: Gap lock+ Record lock,鎖定一個(gè)范圍,并且鎖定記錄本身
Record Locks總是鎖住索引記錄,即使表沒有定義索引,Innodb會(huì)創(chuàng)建一個(gè)隱試的聚集索引來(lái)鎖定。
Next-key Locks默認(rèn)Innodb使用RR的隔離級(jí)別。在這種情況下,InnoDB使用next-key鎖機(jī)制來(lái)查詢數(shù)據(jù)和索引掃描,防止幻象問(wèn)題
Next-key locking結(jié)合了index-row鎖和Gap鎖。當(dāng)搜索和查詢索引操作時(shí),InnoDB使用行鎖的方式,在相應(yīng)的索引記錄上設(shè)置共享或者排他鎖。因此,行級(jí)別的鎖實(shí)際上是索引記錄鎖。而Next-Key鎖是索引記錄鎖加范圍鎖。如果一個(gè)會(huì)話在索引記錄R上加了一個(gè)共享或者排他鎖,其他會(huì)話不能立即插入一個(gè)新的索引記錄在索引記錄R之前的間隙中。
假設(shè)一個(gè)索引的值有10, 11, 13,和20,那么該索引可能被Next-Key Locking的區(qū)間為:
最后一個(gè)間隔范圍,Next-Key實(shí)際上鎖定的范圍是僅僅是最大索引值后面的范圍。
當(dāng)操作的索引是唯一的情況下,Innodb會(huì)對(duì)Next-key Locking進(jìn)行優(yōu)化,將其降級(jí)為Record Lock,只鎖住索引本身,而不是鎖定范圍。
如下:
Session A |
Session B |
Session A>drop table t; |
|
|
Session A>begin; |
#session A提交上面的事務(wù) Session A>commit; |
|
上面的實(shí)驗(yàn)中,表t有1,2,5三個(gè)值。在session A中對(duì)a=5進(jìn)行鎖定讀X鎖定,但因?yàn)樽侄蝍是主鍵(唯一索引),因此此時(shí)鎖定的僅是5這個(gè)索引記錄,而不是(2,5)]這個(gè)范圍,這樣在Session B中能順利的插入a=4(4在(2,5]之間)而不會(huì)阻塞。上述正式因?yàn)镹ext-Key Lock對(duì)唯一索引的記錄降級(jí)為record lock的原因,從而可以提高應(yīng)用的并發(fā)性。
當(dāng)查詢的列是非唯一的索引時(shí),情況如下:
Session A |
Session B |
Session A>drop table t; |
|
注意:右邊的Session B看到15被堵塞,而20沒有被堵塞;所以,推測(cè)此處Gap Lock的范圍是【15,20)和(20,25)。這與官當(dāng)上的http://dev.MySQL.com/doc/refman/5.7/en/innodb-record-level-locks.html舉的例子的 可能的間隔范圍剛好閉開區(qū)間是反的 |
#18在[15,20)之間,被堵塞 |
Gap Locks當(dāng)使用唯一索引查詢唯一的行時(shí),不需要Gap locks.
前面next-key的例子表明gap可能覆蓋一個(gè)單獨(dú)的索引值,多個(gè)索引值,或可能是空的。
例如:下面的語(yǔ)句只需要在id為100的行上使用一個(gè)index-record lock,而不會(huì)影響其他會(huì)話插入數(shù)據(jù):
SELECT * FROM child WHERE id = 100 for update;
如果ID不是索引或者不是一個(gè)uniq index,該語(yǔ)句則使用Gap Locking.
插入意向Gap鎖(insert intention gap lock)在Insert操作之前被設(shè)置。這種鎖的目的是:當(dāng)多個(gè)事務(wù)插入數(shù)據(jù)到相同的索引間隙,只要他們插入的索引間隙內(nèi)的位置不同,則不需要相互等待。假如有索引值4和7,某個(gè)事務(wù)視圖在4和7的間隙間插入5和6,在插入的行會(huì)分配插入意向Gap鎖,但因?yàn)?和6的行并不沖突,所以不會(huì)堵塞對(duì)方。
注意:不同的事務(wù)在一個(gè)間隙(Gap)上可以持有互斥的鎖。例如:當(dāng)事務(wù)B在某個(gè)Gap上擁有一個(gè)排他Gap鎖,事務(wù)A在相同的Gap上可以持有共享Gap鎖。此處允許鎖沖突共存的原因是:當(dāng)從一個(gè)索引上purge一個(gè)記錄,其他事務(wù)對(duì)此記錄加的Gap鎖會(huì)被被合并。
Gap鎖在Innodb中是”完全禁止的”。這意味著它們只能防止其他事務(wù)在一個(gè)Gap中的插入操作。因此,排他Gap鎖和共享Gap鎖具有同樣的效果。
Disabling Gap Locking
Gap鎖可以被完全關(guān)閉方法是設(shè)置事務(wù)隔離級(jí)別修改為RC,或者開啟innodb_locks_unsafe_for_binlog系統(tǒng)變量(此選項(xiàng)5.6和5.7已經(jīng)被棄用)。關(guān)閉Gap的情況下,除了在外鍵一致性檢查和逐漸沖突檢查的時(shí)候,gap鎖均不生效。
RC隔離級(jí)別和開啟innodb_locks_unsafe_for_binlog參數(shù)也會(huì)帶來(lái)其他影響,比如:在mysql分析where條件之后,未匹配行的記錄鎖就會(huì)被釋放(違反了2PL:Two Parsing Lock原則)例如:在update中,innodb執(zhí)行"半一致性"讀,這樣,最新的提交版本被告知mysql,然后由mysql決定行是否匹配執(zhí)行Update操作的where條件。
參考鏈接:
http://dev.mysql.com/doc/refman/5.7/en/innodb-lock-modes.html
http://dev.mysql.com/doc/refman/5.7/en/innodb-record-level-locks.html
http://hedengcheng.com/?p=771#_Toc374698322