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