封鎖的類型以及粒度邢隧,兩段鎖協(xié)議店印,隱式和顯示鎖定。
一倒慧、封鎖粒度
MySQL 中提供了兩種封鎖粒度:
- 行級鎖
- 表級鎖按摘。
應(yīng)該盡量只鎖定需要修改的那部分?jǐn)?shù)據(jù),而不是所有的資源纫谅。鎖定的數(shù)據(jù)量越少炫贤,發(fā)生鎖爭用的可能就越小,系統(tǒng)的并發(fā)程度就越高付秕。
但是加鎖需要消耗資源兰珍,鎖的各種操作(包括獲取鎖、釋放鎖询吴、以及檢查鎖狀態(tài))都會增加系統(tǒng)開銷掠河。因此封鎖粒度越小亮元,系統(tǒng)開銷就越大。
在選擇封鎖粒度時(shí)唠摹,需要在鎖開銷和并發(fā)程度之間做一個權(quán)衡爆捞。
二、封鎖類型
1. 讀寫鎖
- 互斥鎖(Exclusive)跃闹,簡寫為 X 鎖嵌削,又稱寫鎖。
- 共享鎖(Shared)望艺,簡寫為 S 鎖苛秕,又稱讀鎖。
有以下兩個規(guī)定:
- 一個事務(wù)對數(shù)據(jù)對象 A 加了 X 鎖找默,就可以對 A 進(jìn)行讀取和更新艇劫。加鎖期間其它事務(wù)不能對 A 加任何鎖。
- 一個事務(wù)對數(shù)據(jù)對象 A 加了S 鎖惩激,可以對 A 進(jìn)行讀取操作店煞,但是不能進(jìn)行更新操作。加鎖期間其它事務(wù)能對 A 加 S 鎖风钻,但是不能加 X 鎖顷蟀。
2. 意向鎖
意向鎖的含義
意向鎖的含義是如果對一個結(jié)點(diǎn)加意向鎖,則說明該結(jié)點(diǎn)的下層結(jié)點(diǎn)正在被加鎖骡技;對任一結(jié)點(diǎn)加鎖時(shí)鸣个,必須先對它的上層結(jié)點(diǎn)加意向鎖。
例如布朦,對任一元組加鎖時(shí)囤萤,必須先對它所在的關(guān)系加意向鎖。
于是是趴,事務(wù)T要對關(guān)系R1加 X鎖時(shí)涛舍,系統(tǒng)只要檢查根結(jié)點(diǎn)數(shù)據(jù)庫和關(guān)系R1是否己加了不相容的鎖,而不再需要搜索和檢查尺中的每一個元組是否加了X鎖唆途。
意向鎖的作用
引進(jìn)意向鎖是為了提高封鎖子系統(tǒng)的效率富雅。該封鎖子系統(tǒng)支持多種封鎖粒度。原因是:在多粒度封鎖方法中一個數(shù)據(jù)對象可能以兩種方式加鎖 ― 顯式封鎖和隱式封鎖肛搬。因此系統(tǒng)在對某一數(shù)據(jù)對象加鎖時(shí)不僅要檢查該數(shù)據(jù)對象上有無(顯式和隱式)封鎖與之沖突吹榴,還要檢查其所有上級結(jié)點(diǎn)和所有下級結(jié)點(diǎn),看申請的封鎖是否與這些結(jié)點(diǎn)上的(顯式和隱式)封鎖沖突滚婉,顯然,這樣的檢查方法效率很低帅刀。為此引進(jìn)了意向鎖让腹。意向鎖的含義是:對任一結(jié)點(diǎn)加鎖時(shí)远剩,必須先對它的上層結(jié)點(diǎn)加意向鎖。例如事務(wù) T 要對某個元組加 X 鎖骇窍,則首先要對關(guān)系和數(shù)據(jù)庫加 ix 鎖瓜晤。換言之,對關(guān)系和數(shù)據(jù)庫加 ix 鎖腹纳,表示它的后裔結(jié)點(diǎn) ― 某個元組擬(意向)加 X 鎖痢掠。引進(jìn)意向鎖后,系統(tǒng)對某一數(shù)據(jù)對象加鎖時(shí)不必逐個檢查與下一級結(jié)點(diǎn)的封鎖沖突了嘲恍。例如足画,事務(wù) T 要對關(guān)系 R 加 X 鎖時(shí),系統(tǒng)只要檢查根結(jié)點(diǎn)數(shù)據(jù)庫和 R 本身是否已加了不相容的鎖(如發(fā)現(xiàn)已經(jīng)加了 ix 佃牛,則與 X 沖突)淹辞,而不再需要搜索和檢查 R 中的每一個元組是否加了 X 鎖或 S 鎖。
使用意向鎖(Intention Locks)可以更容易地支持多粒度封鎖俘侠。
在存在行級鎖和表級鎖的情況下象缀,事務(wù) T 想要對表 A 加 X 鎖,就需要先檢測是否有其它事務(wù)對表 A 或者表 A 中的任意一行加了鎖爷速,那么就需要對表 A 的每一行都檢測一次央星,這是非常耗時(shí)的。
意向鎖在原來的 X/S 鎖之上引入了 IX/IS惫东,IX/IS 都是表鎖莉给,用來表示一個事務(wù)想要在表中的某個數(shù)據(jù)行上加 X 鎖或 S 鎖。有以下兩個規(guī)定:
- 一個事務(wù)在獲得某個數(shù)據(jù)行對象的 S 鎖之前凿蒜,必須先獲得表的 IS 鎖或者更強(qiáng)的鎖禁谦;
- 一個事務(wù)在獲得某個數(shù)據(jù)行對象的 X 鎖之前,必須先獲得表的 IX 鎖废封。
通過引入意向鎖州泊,事務(wù) T 想要對表 A 加 X 鎖,只需要先檢測是否有其它事務(wù)對表 A 加了 X/IX/S/IS 鎖漂洋,如果加了就表示有其它事務(wù)正在使用這個表或者表中某一行的鎖遥皂,因此事務(wù) T 加 X 鎖失敗。
解釋如下:
- 任意 IS/IX 鎖之間都是兼容的刽漂,因?yàn)樗鼈冎槐硎鞠胍獙Ρ砑渔i演训,而不是真正加鎖;
- 這里兼容關(guān)系針對的是表級鎖贝咙,而表級的 IX 鎖和行級的 X 鎖兼容样悟,兩個事務(wù)可以對兩個數(shù)據(jù)行加 X 鎖。(事務(wù) T1 想要對數(shù)據(jù)行 R1 加 X 鎖,事務(wù) T2 想要對同一個表的數(shù)據(jù)行 R2 加 X 鎖窟她,兩個事務(wù)都需要對該表加 IX 鎖陈症,但是 IX 鎖是兼容的,并且 IX 鎖與行級的 X 鎖也是兼容的震糖,因此兩個事務(wù)都能加鎖成功录肯,對同一個表中的兩個數(shù)據(jù)行做修改。)
三吊说、封鎖協(xié)議
1. 三級封鎖協(xié)議
一級封鎖協(xié)議
事務(wù) T 要修改數(shù)據(jù) A 時(shí)必須加 X 鎖论咏,直到 T 結(jié)束才釋放鎖。
可以解決丟失修改問題颁井,因?yàn)椴荒芡瑫r(shí)有兩個事務(wù)對同一個數(shù)據(jù)進(jìn)行修改厅贪,那么事務(wù)的修改就不會被覆蓋。
二級封鎖協(xié)議
在一級的基礎(chǔ)上蚤蔓,要求讀取數(shù)據(jù) A 時(shí)必須加 S 鎖卦溢,讀取完馬上釋放 S 鎖。
可以解決讀臟數(shù)據(jù)問題秀又,因?yàn)槿绻粋€事務(wù)在對數(shù)據(jù) A 進(jìn)行修改单寂,根據(jù) 1 級封鎖協(xié)議,會加 X 鎖吐辙,那么就不能再加 S 鎖了宣决,也就是不會讀入數(shù)據(jù)。
三級封鎖協(xié)議
在二級的基礎(chǔ)上昏苏,要求讀取數(shù)據(jù) A 時(shí)必須加 S 鎖尊沸,直到事務(wù)結(jié)束了才能釋放 S 鎖。
可以解決不可重復(fù)讀的問題贤惯,因?yàn)樽x A 時(shí)洼专,其它事務(wù)不能對 A 加 X 鎖,從而避免了在讀的期間數(shù)據(jù)發(fā)生改變孵构。
2. 兩段鎖協(xié)議
加鎖和解鎖分為兩個階段進(jìn)行屁商。
調(diào)度兩段鎖協(xié)議:是指所有的事務(wù)必須分兩個階段對數(shù)據(jù)項(xiàng)加鎖和解鎖。即事務(wù)分兩個階段颈墅,第一個階段是獲得封鎖蜡镶。事務(wù)可以獲得任何數(shù)據(jù)項(xiàng)上的任何類型的鎖,但是不能釋放恤筛;第二階段是釋放封鎖官还,事務(wù)可以釋放任何數(shù)據(jù)項(xiàng)上的任何類型的鎖,但不能申請毒坛。
第一階段是獲得封鎖的階段望伦,稱為擴(kuò)展階段:其實(shí)也就是該階段可以進(jìn)入加鎖操作林说,在對任何數(shù)據(jù)進(jìn)行讀操作之前要申請獲得S鎖,在進(jìn)行寫操作之前要申請并獲得X鎖屯伞,加鎖不成功述么,則事務(wù)進(jìn)入等待狀態(tài),直到加鎖成功才繼續(xù)執(zhí)行愕掏。就是加鎖后就不能解鎖了。
第二階段是釋放封鎖的階段顶伞,稱為收縮階段:當(dāng)事務(wù)釋放一個封鎖后饵撑,事務(wù)進(jìn)入封鎖階段,在該階段只能進(jìn)行解鎖而不能再進(jìn)行加鎖操作唆貌。
可串行化調(diào)度
多個事務(wù)的并發(fā)執(zhí)行是正確的滑潘,當(dāng)且僅當(dāng)其結(jié)果與按某一次序串行地執(zhí)行這些事務(wù)時(shí)結(jié)果相同。
可串行性(Serializability)是并發(fā)事務(wù)正確調(diào)度的準(zhǔn)則锨咙。一個給定的并發(fā)調(diào)度语卤,當(dāng)且僅當(dāng)它是可串行化的,才是正確的酪刀。
DBMS為了保證并發(fā)調(diào)度的正確性粹舵,普遍使用兩段鎖協(xié)議實(shí)現(xiàn)并發(fā)調(diào)度的可串行性,保證調(diào)度的正確性骂倘。
兩段鎖協(xié)議
- 在對任何數(shù)據(jù)進(jìn)行讀眼滤、寫操作之前,事務(wù)首先要申請并獲得對該數(shù)據(jù)的封鎖历涝;
- 在釋放一個封鎖之后诅需,事務(wù)不再申請和獲得任何其他封鎖。
若并發(fā)的所有事務(wù)均遵守兩段鎖協(xié)議荧库,則對這些事務(wù)的任何并發(fā)調(diào)度策略都是可串行化的堰塌。
兩段鎖協(xié)議和防止死鎖的一次封鎖法
- 一次封鎖法要求每個事務(wù)必須一次將所有要使用的數(shù)據(jù)全部加鎖,否則不能繼續(xù)執(zhí)行分衫。一次封鎖法遵循兩段鎖協(xié)議场刑;
- 兩段鎖協(xié)議并不要求事務(wù)必須一次將所有要使用的數(shù)據(jù)全部加鎖,因此遵循兩段鎖協(xié)議的事務(wù)可能發(fā)生死鎖丐箩。
事務(wù)遵循兩段鎖協(xié)議是保證可串行化調(diào)度的充分條件摇邦。例如以下操作滿足兩段鎖協(xié)議,它是可串行化調(diào)度屎勘。
lock-x(A)...lock-s(B)...lock-s(C)...unlock(A)...unlock(C)...unlock(B)
但不是必要條件施籍,例如以下操作不滿足兩段鎖協(xié)議,但它還是可串行化調(diào)度概漱。
lock-x(A)...unlock(A)...lock-s(B)...unlock(B)...lock-s(C)...unlock(C)
四丑慎、MySQL隱式與顯示鎖定
當(dāng)多個客戶端并發(fā)訪問同一個數(shù)據(jù)的時(shí)候,為了保證數(shù)據(jù)的一致性,數(shù)據(jù)庫管理系統(tǒng)會自動的為該數(shù)據(jù)加鎖竿裂、解鎖玉吁,這種鎖被稱為隱式鎖。隱式鎖無需開發(fā)人員維護(hù)(包括鎖粒度腻异、加鎖時(shí)機(jī)进副、解鎖時(shí)機(jī)等)
某些特殊情況下需要開發(fā)人員手動的進(jìn)行加鎖、解鎖悔常,這種鎖方式被稱為顯示鎖影斑。對于顯示鎖而言,開發(fā)人員不僅要確定鎖的粒度机打,還需要確定加鎖的時(shí)機(jī)(何時(shí)加鎖)矫户、解鎖的時(shí)機(jī)(何時(shí)解鎖)以及鎖的類型
MySQL 的 InnoDB 存儲引擎采用兩段鎖協(xié)議,會根據(jù)隔離級別在需要的時(shí)候自動加鎖残邀,并且所有的鎖都是在同一時(shí)刻被釋放皆辽,這被稱為隱式鎖定。
InnoDB 也可以使用特定的語句進(jìn)行顯示鎖定:
SELECT ... LOCK In SHARE MODE;
SELECT ... FOR UPDATE;