摘要:表級(jí)鎖表級(jí)鎖表級(jí)別的鎖定是各存儲(chǔ)引擎中最大顆粒度的鎖定機(jī)制。當(dāng)前沒(méi)有其他事務(wù)持有表中任意一行的排他鎖。為了檢測(cè)是否滿足第二個(gè)條件,事務(wù)必須在確保表不存在任何排他鎖的前提下,去檢測(cè)表中的每一行是否存在排他鎖。
數(shù)據(jù)庫(kù)鎖定機(jī)制簡(jiǎn)單來(lái)說(shuō),就是數(shù)據(jù)庫(kù)為了保證數(shù)據(jù)的一致性,而使各種共享資源在被并發(fā)訪問(wèn)變得有序所設(shè)計(jì)的一種規(guī)則。
MySQL數(shù)據(jù)庫(kù)由于其自身架構(gòu)的特點(diǎn),存在多種數(shù)據(jù)存儲(chǔ)引擎,每種存儲(chǔ)引擎的鎖定機(jī)制都是為各自所面對(duì)的特定場(chǎng)景而優(yōu)化設(shè)計(jì),所以各存儲(chǔ)引擎的鎖定機(jī)制也有較大區(qū)別。
MySQL各存儲(chǔ)引擎使用了三種類型(級(jí)別)的鎖定機(jī)制:表級(jí)鎖定
,行級(jí)鎖定
和頁(yè)級(jí)鎖定
。
表級(jí)別的鎖定是MySQL各存儲(chǔ)引擎中最大顆粒度的鎖定機(jī)制。該鎖定機(jī)制最大的特點(diǎn)是實(shí)現(xiàn)邏輯非常簡(jiǎn)單,帶來(lái)的系統(tǒng)負(fù)面影響最小。所以獲取鎖和釋放鎖的速度很快。
當(dāng)然,鎖定顆粒度大所帶來(lái)最大的負(fù)面影響就是出現(xiàn)鎖定資源爭(zhēng)用的概率也會(huì)最高,致使并發(fā)度大打折扣。
使用表級(jí)鎖定的主要是MyISAM,MEMORY,CSV等一些非事務(wù)性存儲(chǔ)引擎。
行級(jí)鎖定最大的特點(diǎn)就是鎖定對(duì)象的顆粒度很小,由于鎖定顆粒度很小,所以發(fā)生鎖定資源爭(zhēng)用的概率也最小,能夠給予應(yīng)用程序盡可能大的并發(fā)處理能力而提高一些需要高并發(fā)應(yīng)用系統(tǒng)的整體性能。
雖然能夠在并發(fā)處理能力上面有較大的優(yōu)勢(shì),但是行級(jí)鎖定也因此帶來(lái)了不少弊端。
由于鎖定資源的顆粒度很小,所以每次獲取鎖和釋放鎖需要做的事情也更多,帶來(lái)的消耗自然也就更大了。此外,行級(jí)鎖定也最容易發(fā)生死鎖。
使用行級(jí)鎖定的主要是InnoDB存儲(chǔ)引擎
。
頁(yè)級(jí)鎖定是MySQL中比較獨(dú)特的一種鎖定級(jí)別。頁(yè)級(jí)鎖定的特點(diǎn)是鎖定顆粒度介于行級(jí)鎖定與表級(jí)鎖之間,所以獲取鎖定所需要的資源開(kāi)銷,以及所能提供的并發(fā)處理能力也同樣是介于上面二者之間。
使用頁(yè)級(jí)鎖定的主要是BerkeleyDB存儲(chǔ)引擎。
總的來(lái)說(shuō),MySQL這3種鎖的特性可大致歸納如下:
表級(jí)鎖
:開(kāi)銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低;
行級(jí)鎖
:開(kāi)銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高;
頁(yè)面鎖
:開(kāi)銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般。
InnoDB 實(shí)現(xiàn)了標(biāo)準(zhǔn)的行級(jí)鎖,包括兩種:共享鎖(簡(jiǎn)稱 s 鎖)、排它鎖(簡(jiǎn)稱 x 鎖)。
對(duì)于共享鎖而言,對(duì)當(dāng)前行加共享鎖,不會(huì)阻塞其他事務(wù)對(duì)同一行的讀請(qǐng)求,但會(huì)阻塞對(duì)同一行的寫請(qǐng)求。只有當(dāng)讀鎖釋放后,才會(huì)執(zhí)行其它事物的寫操作。
對(duì)于排它鎖而言,會(huì)阻塞其他事務(wù)對(duì)同一行的讀和寫操作,只有當(dāng)寫鎖釋放后,才會(huì)執(zhí)行其它事務(wù)的讀寫操作。
簡(jiǎn)而言之,就是讀鎖會(huì)阻塞寫(X),但是不會(huì)堵塞讀(S)。而寫鎖則會(huì)把讀(S)和寫(X)都堵塞
對(duì)于InnoDB 在RR(MySQL默認(rèn)隔離級(jí)別) 而言,對(duì)于 update、delete 和 insert 語(yǔ)句, 會(huì)自動(dòng)給涉及數(shù)據(jù)集加排它鎖(X);
對(duì)于普通 select 語(yǔ)句,innodb 不會(huì)加任何鎖。如果想在select操作的時(shí)候加上 S鎖 或者 X鎖,需要我們手動(dòng)加鎖。
-- 加共享鎖(S)select * from table_name where ... lock in share mode-- 加排它鎖(X)select * from table_name where ... for update
用 select... in share mode 獲得共享鎖,主要用在需要數(shù)據(jù)依存關(guān)系時(shí)來(lái)確認(rèn)某行記錄是否存在,并確保沒(méi)有人對(duì)這個(gè)記錄進(jìn)行 update 或者 delete 操作。
但是如果當(dāng)前事務(wù)也需要對(duì)該記錄進(jìn)行更新操作,則有可能造成死鎖,對(duì)于鎖定行記錄后需要進(jìn)行更新操作的應(yīng)用,應(yīng)該使用 select... for update 方式獲得排他鎖。
記錄鎖其實(shí)很好理解,對(duì)表中的記錄加鎖,叫做記錄鎖,簡(jiǎn)稱行鎖。比如
SELECT * FROM `test` WHERE `id`=1 FOR UPDATE;
它會(huì)在 id=1 的記錄上加上記錄鎖,以阻止其他事務(wù)插入,更新,刪除 id=1 這一行。
需要注意的是:
- d 列必須為唯一索引列或主鍵列,否則上述語(yǔ)句加的鎖就會(huì)變成臨鍵鎖(有關(guān)臨鍵鎖下面會(huì)講)。- 同時(shí)查詢語(yǔ)句必須為精準(zhǔn)匹配(=),不能為 >、<、like等,否則也會(huì)退化成臨鍵鎖。
其他實(shí)現(xiàn)
在通過(guò) 主鍵索引 與 唯一索引 對(duì)數(shù)據(jù)行進(jìn)行 UPDATE 操作時(shí),也會(huì)對(duì)該行數(shù)據(jù)加記錄鎖:
-- id 列為主鍵列或唯一索引列 UPDATE SET age = 50 WHERE id = 1;
記錄鎖是鎖住記錄,鎖住索引記錄,而不是真正的數(shù)據(jù)記錄.
如果要鎖的列沒(méi)有索引,進(jìn)行全表記錄加鎖
記錄鎖也是排它(X)鎖
,所以會(huì)阻塞其他事務(wù)對(duì)其插入、更新、刪除。
間隙鎖 是 Innodb 在 RR(可重復(fù)讀) 隔離級(jí)別 下為了解決幻讀問(wèn)題
時(shí)引入的鎖機(jī)制。間隙鎖是innodb中行鎖的一種。
請(qǐng)務(wù)必牢記:使用間隙鎖鎖住的是一個(gè)區(qū)間,而不僅僅是這個(gè)區(qū)間中的每一條數(shù)據(jù)。
舉例來(lái)說(shuō),假如emp表中只有101條記錄,其empid的值分別是1,2,...,100,101,下面的SQL:
SELECT * FROM emp WHERE empid > 100 FOR UPDATE
當(dāng)我們用條件檢索數(shù)據(jù),并請(qǐng)求共享或排他鎖時(shí),InnoDB不僅會(huì)對(duì)符合條件的empid值為101的記錄加鎖,也會(huì)對(duì)empid大于101(這些記錄并不存在)的“間隙”加鎖。
這個(gè)時(shí)候如果你插入empid等于102的數(shù)據(jù)的,如果那邊事物還沒(méi)有提交,那你就會(huì)處于等待狀態(tài),無(wú)法插入數(shù)據(jù)。
有關(guān)間隙鎖所需講的東西還是蠻多的,我會(huì)多帶帶寫一篇文章來(lái)分析間隙鎖,并在文章中附上完整的示例。
Next-key鎖是記錄鎖和間隙鎖的組合,它指的是加在某條記錄以及這條記錄前面間隙上的鎖。
也可以理解為一種特殊的間隙鎖。通過(guò)臨建鎖可以解決幻讀
的問(wèn)題。 每個(gè)數(shù)據(jù)行上的非唯一索引列上都會(huì)存在一把臨鍵鎖,當(dāng)某個(gè)事務(wù)持有該數(shù)據(jù)行的臨鍵鎖時(shí),會(huì)鎖住一段左開(kāi)右閉區(qū)間的數(shù)據(jù)。需要強(qiáng)調(diào)的一點(diǎn)是,
InnoDB 中行級(jí)鎖是基于索引實(shí)現(xiàn)的。
臨鍵鎖只與 非唯一索引列 有關(guān),在 唯一索引列(包括主鍵列)上不存在臨鍵鎖。
假設(shè)有如下表:
id主鍵, age 普通索引
該表中 age 列潛在的臨鍵鎖有:
(-∞, 10],
(10, 24],
(24, 32],
(32, 45],
(45, +∞],
在事務(wù) A 中執(zhí)行如下命令:
-- 根據(jù)非唯一索引列 UPDATE 某條記錄 UPDATE table SET name = Vladimir WHERE age = 24; -- 或根據(jù)非唯一索引列 鎖住某條記錄 SELECT * FROM table WHERE age = 24 FOR UPDATE;
不管執(zhí)行了上述 SQL 中的哪一句,之后如果在事務(wù) B 中執(zhí)行以下命令,則該命令會(huì)被阻塞:
INSERT INTO table VALUES(100, 26, tianqi);
很明顯,事務(wù) A 在對(duì) age 為 24 的列進(jìn)行 UPDATE 操作的同時(shí),也獲取了 (24, 32] 這個(gè)區(qū)間內(nèi)的臨鍵鎖。
總結(jié)
這里對(duì) 記錄鎖、間隙鎖、臨鍵鎖 做一個(gè)總結(jié)
表鎖
。意向鎖又分為 意向共享鎖(IS)
和 意向排他鎖(IX)
-- 事務(wù)要獲取某些行的 S 鎖,必須先獲得表的 IS 鎖。 SELECT column FROM table ... LOCK IN SHARE MODE;
-- 事務(wù)要獲取某些行的 X 鎖,必須先獲得表的 IX 鎖。 SELECT column FROM table ... FOR UPDATE;
首先我們要明白四點(diǎn)
這里就會(huì)有疑惑,既然前面已經(jīng)有了共享鎖(S鎖)、排它鎖(X鎖)。那么為什么需要引入意向鎖呢?它能解決什么問(wèn)題呢?
我們可以理解 意向鎖 存在的目的就是 為了讓 InnoDB 中的行鎖和表鎖更高效的共存
。
為什么這么說(shuō),我們來(lái)舉一個(gè)例子。
舉例
下面有一張表 InnoDB RR隔離級(jí)別 id是主鍵
事務(wù) A 獲取了某一行的排他鎖,并未提交:
SELECT * FROM users WHERE id = 6 FOR UPDATE;
事務(wù) B 想要獲取users表的表鎖:
LOCK TABLES users READ;
因?yàn)楣蚕礞i與排他鎖互斥,所以事務(wù) B 在視圖對(duì) users 表加共享鎖的時(shí)候,必須保證:
為了檢測(cè)是否滿足第二個(gè)條件,事務(wù) B 必須在確保users表不存在任何排他鎖的前提下,去檢測(cè)表中的每一行是否存在排他鎖。很明顯這是一個(gè)效率很差的做法,但是有了意向鎖之后,情況就不一樣了:事務(wù)B只要看表上有沒(méi)有
意向共享鎖,有則說(shuō)明表中有些行被共享行鎖鎖住了,因此,事務(wù)B申請(qǐng)表的寫鎖會(huì)被阻塞。這樣是不是就高效多了。
這也解釋就應(yīng)該清楚,為什么有意向鎖這個(gè)東西存在了。
我們可以舉個(gè)生活中的例子,再來(lái)理解下為什么需要存在意向鎖。
打個(gè)比方,就像有個(gè)游樂(lè)場(chǎng),很多小朋友進(jìn)去玩,看門大爺如果要下班鎖游樂(lè)場(chǎng)的門(加表鎖),他必須確保每個(gè)角落都要去檢查一遍,確保每個(gè)小朋友都離開(kāi)了(釋放行鎖),才可以鎖門。
假設(shè)鎖門是件頻繁發(fā)生的事情,大爺就會(huì)非常崩潰。那大爺想了一個(gè)辦法,每個(gè)小朋友進(jìn)入,就把自己的名字寫在本子上,小朋友離開(kāi),就把自己的名字劃掉,那大爺就能方便掌握有沒(méi)有小朋友在游樂(lè)場(chǎng)里,不必每個(gè)角落都去尋找一遍。
例子中的“小本子”,就是意向鎖,他記錄的信息并不精細(xì),他只是提醒大爺,有人在屋里。
這里我們?cè)賮?lái)看下 共享(S)鎖、排他(X)鎖、意向共享鎖(IS)、意向排他鎖(IX)的兼容性
可以看出 意向鎖之間是互相兼容的.那你存在的意義是啥?
意向鎖不會(huì)為難意向鎖。也不會(huì)為難行級(jí)排他(X)/共享(X)鎖,它的存在是為難表級(jí)
排他(X)/共享(X)鎖。
注意
這里的排他(X)/共享(S)鎖指的都是表鎖!意向鎖不會(huì)與行級(jí)的共享/排他鎖互斥! 行級(jí)別的X和S按照上面的兼容性規(guī)則即可。
意向鎖與意向鎖之間永遠(yuǎn)是兼容的,因?yàn)楫?dāng)你不論加行級(jí)的X鎖或S鎖,都會(huì)自動(dòng)獲取表級(jí)的IX鎖或者IS鎖。也就是你有10個(gè)事務(wù),對(duì)不同的10行加了行級(jí)X鎖,那么這個(gè)時(shí)候就存在10個(gè)IX鎖。
這10IX存在的目的是啥呢,就是假如這個(gè)時(shí)候有個(gè)事務(wù),想對(duì)整個(gè)表加排它X鎖,那它不需要遍歷每一行是否存在S或X鎖,而是看有沒(méi)有存在意向鎖,只要存在一個(gè)意向鎖,那這個(gè)事務(wù)就加不了表級(jí)排它X鎖,要等上面10個(gè)IX全部釋放才行。
在講解插入意向鎖之前,先來(lái)思考一個(gè)問(wèn)題
下面有張表 id主鍵,age普通索引
首先事務(wù) A 插入了一行數(shù)據(jù),并且沒(méi)有 commit:
INSERT INTO users SELECT 4, Bill, 15;
隨后事務(wù) B 試圖插入一行數(shù)據(jù):
INSERT INTO users SELECT 5, Louis, 16;
請(qǐng)問(wèn):
1、事務(wù)A使用了什么鎖?
2、 事務(wù) B 是否會(huì)被事務(wù) A 阻塞?
插入意向鎖是在插入一條記錄行前,由 INSERT 操作產(chǎn)生的一種間隙鎖
。
該鎖用以表示插入意向,當(dāng)多個(gè)事務(wù)在同一區(qū)間(gap)插入位置不同的多條數(shù)據(jù)時(shí),事務(wù)之間不需要互相等待。
假設(shè)存在兩條值分別為 4 和 7 的記錄,兩個(gè)不同的事務(wù)分別試圖插入值為 5 和 6 的兩條記錄,每個(gè)事務(wù)在獲取插入行上獨(dú)占的(排他)鎖前,都會(huì)獲?。?,7)之間的間隙鎖,但是因?yàn)閿?shù)據(jù)行之間并不沖突,所以兩個(gè)事務(wù)之間
并不會(huì)產(chǎn)生沖突(阻塞等待)。
總結(jié)來(lái)說(shuō),插入意向鎖 的特性可以分成兩部分:
需要強(qiáng)調(diào)的是,雖然插入意向鎖中含有意向鎖三個(gè)字,但是它并不屬于意向鎖而屬于間隙鎖,因?yàn)?strong>意向鎖是表鎖而插入意向鎖是行鎖
。
現(xiàn)在我們可以回答開(kāi)頭的問(wèn)題了:
1、 使用插入意向鎖與記錄鎖。
2、事務(wù) A 不會(huì)阻塞事務(wù) B。
為什么不用間隙鎖
如果只是使用普通的間隙鎖會(huì)怎么樣呢?我們?cè)诳词聞?wù)A,其實(shí)它一共獲取了3把鎖
最終,事務(wù) A 插入了該行數(shù)據(jù),并鎖住了(10,20)這個(gè)區(qū)間。
隨后事務(wù) B 試圖插入一行數(shù)據(jù):
INSERT INTO users SELECT 5, Louis, 16;
因?yàn)?16 位于(15,20)區(qū)間內(nèi),而該區(qū)間內(nèi)又存在一把間隙鎖,所以事務(wù) B 別說(shuō)想申請(qǐng)自己的間隙鎖了,它甚至不能獲取該行的記錄鎖,自然只能乖乖的等待 事務(wù) A結(jié)束,才能執(zhí)行插入操作。
很明顯,這樣做事務(wù)之間將會(huì)頻發(fā)陷入阻塞等待,插入的并發(fā)性非常之差。這時(shí)如果我們?cè)偃セ叵胛覀儎倓傊v過(guò)的插入意向鎖,就不難發(fā)現(xiàn)它是如何優(yōu)雅的解決了并發(fā)插入的問(wèn)題。
總結(jié)
- InnoDB在RR的事務(wù)隔離級(jí)別下,使用插入意向鎖來(lái)控制和解決并發(fā)插入。- 插入意向鎖是一種特殊的間隙鎖。- 插入意向鎖在鎖定區(qū)間相同但記錄行本身不沖突的情況下互不排斥。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://hztianpu.com/yun/124544.html
摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語(yǔ)言和等其他語(yǔ)言的對(duì)比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問(wèn)到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過(guò)的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語(yǔ)言和Java、python等其他語(yǔ)言的對(duì)比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...
摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語(yǔ)言和等其他語(yǔ)言的對(duì)比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問(wèn)到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過(guò)的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語(yǔ)言和Java、python等其他語(yǔ)言的對(duì)比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...
摘要:關(guān)系型數(shù)據(jù)庫(kù)中的事務(wù)管理詳解并發(fā)控制與事務(wù)日志數(shù)據(jù)庫(kù)系統(tǒng)的萌芽出現(xiàn)于年代。并發(fā)控制并發(fā)控制旨在針對(duì)數(shù)據(jù)庫(kù)中對(duì)事務(wù)并行的場(chǎng)景,保證中的一致性與隔離性。絕大部分?jǐn)?shù)據(jù)庫(kù)會(huì)采用鎖或者數(shù)據(jù)版本控制的方式來(lái)處理并發(fā)控制問(wèn)題。 本文節(jié)選自:關(guān)系型數(shù)據(jù)庫(kù)理論 https://url.wx-coder.cn/DJNQn ,涉及引用/整理的文章列舉在了 Database-List。 showImg(htt...
閱讀 945·2023-04-25 19:43
閱讀 4247·2021-11-30 14:52
閱讀 4032·2021-11-30 14:52
閱讀 4136·2021-11-29 11:00
閱讀 4025·2021-11-29 11:00
閱讀 4162·2021-11-29 11:00
閱讀 3873·2021-11-29 11:00
閱讀 6775·2021-11-29 11:00