深入理解MySQL的行級鎖
??概述
鎖是計算機協(xié)調多個進程或線程并發(fā)訪問某一資源的機制。在數據庫中,除傳統(tǒng)的計算資源(CPU、RAM、I/O)的爭用以外,數據也是一種供許多用戶共享的資源。
如何保證數據并發(fā)訪問的一致性、有效性是所有數據庫必須解決的一個問題,鎖沖突也是影響數據庫并發(fā)訪問性能的一個重要因素。從這個角度來說,鎖對數據庫而言顯得尤其重要,也更加復雜。
MySQL中的鎖,按照鎖的粒度分,分為以下三類:
- 全局鎖:鎖定數據庫中的所有表。
- 表級鎖:每次操作鎖住某一張表。
- 行級鎖:每次操作鎖住對應的行數據。
??行級鎖介紹
行級鎖,每次操作鎖住對應的行數據。鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度最高。應用在InnoDB存儲引擎中。
InnoDB的數據是基于索引組織的,行鎖是通過對索引上的索引項加鎖來實現(xiàn)的,而不是對記錄加的鎖。
對于行級鎖,主要分為以下三類:
行鎖(Record Lock):鎖定單個行記錄的鎖,防止其他事務對此行進行update和delete。在RC、RR隔離級別下都支持。
- 間隙鎖(Gap Lock):鎖定索引記錄間隙(不含該記錄),確保索引記錄間隙不變,防止其他事務在這個間隙進行insert,產生幻讀。在RR隔離級別下支持。

臨鍵鎖(Next-Key Lock):行鎖和間隙鎖組合,同時鎖住數據,并鎖住數據前面的間隙Gap。在RR隔離級別下支持。

??行鎖
????介紹
InnoDB 實現(xiàn)了以下兩種類型的行鎖:
- 共享鎖(S):允許一個事務去讀一行,阻止其他事務獲得相同數據集的排它鎖。
- 排他鎖(X):允許獲取排他鎖的事務更新數據,阻止其他事務獲得相同數據集的共享鎖和排他鎖。
兩種行鎖的兼容情況如下:
| 鎖類型 | S | X |
|---|---|---|
| S | 兼容 | 沖突 |
| X | 沖突 | 兼容 |
常見的SQL語句,在執(zhí)行時,所加的行鎖如下:

????演示
默認情況下,InnoDB 在 REPEATABLE READ 事務隔離級別運行,InnoDB 使用 next-key 鎖進行搜索和索引掃描,以防止幻讀。
● 針對唯一索引進行檢索時,對已存在的記錄進行等值匹配時,將會自動優(yōu)化為行鎖。
● InnoDB的行鎖是針對于索引加的鎖,不通過索引條件檢索數據,那么InnoDB將對表中的所有記錄加鎖,此時 就會升級為表鎖。
可以通過以下SQL,查看意向鎖及行鎖的加鎖情況:
A. 普通的select語句,執(zhí)行時,不會加鎖。
B. select…lock in share mode,加共享鎖,共享鎖與共享鎖之間兼容。
共享鎖與排他鎖之間互斥。
客戶端一獲取的是id為1這行的共享鎖,客戶端二是可以獲取id為3這行的排它鎖的,因為不是同一行數據。 而如果客戶端二想獲取id為1這行的排他鎖,會處于阻塞狀態(tài),以為共享鎖與排他鎖之間互斥。
C. 排它鎖與排他鎖之間互斥
當客戶端一,執(zhí)行update語句,會為id為1的記錄加排他鎖; 客戶端二,如果也執(zhí)行update語句更新id為1的數據,也要為id為1的數據加排他鎖,但是客戶端二會處于阻塞狀態(tài),因為排他鎖之間是互斥的。 直到客戶端一,把事務提交了,才會把這一行的行鎖釋放,此時客戶端二,解除阻塞。
D. 無索引行鎖升級為表鎖
我們在兩個客戶端中執(zhí)行如下操作:
在客戶端一中,開啟事務,并執(zhí)行update語句,更新name為Lily的數據,也就是id為19的記錄 。然后在客戶端二中更新id為3的記錄,卻不能直接執(zhí)行,會處于阻塞狀態(tài),為什么呢?
原因就是因為此時,客戶端一,根據name字段進行更新時,name字段是沒有索引的,如果沒有索引,此時行鎖會升級為表鎖(因為行鎖是對索引項加的鎖,而name沒有索引)。
接下來,我們再針對name字段建立索引,索引建立之后,再次做一個測試:
此時我們可以看到,客戶端一,開啟事務,然后依然是根據name進行更新。而客戶端二,在更新id為3的數據時,更新成功,并未進入阻塞狀態(tài)。 這樣就說明,我們根據索引字段進行更新操作,就可以避免行鎖升級為表鎖的情況。
??間隙鎖&臨鍵鎖
默認情況下,InnoDB在 REPEATABLE READ事務隔離級別運行,InnoDB使用 next-key 鎖進行搜索和索引掃描,以防止幻讀。
- 索引上的等值查詢(唯一索引),給不存在的記錄加鎖時, 優(yōu)化為間隙鎖 。
- 索引上的等值查詢(非唯一普通索引),向右遍歷時最后一個值不滿足查詢需求時,next-key lock 退化為間隙鎖。
- 索引上的范圍查詢(唯一索引)–會訪問到不滿足條件的第一個值為止。
注意:
間隙鎖唯一目的是防止其他事務插入間隙。間隙鎖可以共存,一個事務采用的間隙鎖不會阻止另一個事務在同一間隙上采用間隙鎖。
示例演示
A. 索引上的等值查詢(唯一索引),給不存在的記錄加鎖時, 優(yōu)化為間隙鎖 。

B. 索引上的等值查詢(非唯一普通索引),向右遍歷時最后一個值不滿足查詢需求時,next-key lock 退化為間隙鎖。
介紹分析一下:
我們知道InnoDB的B+樹索引,葉子節(jié)點是有序的雙向鏈表。 假如,我們要根據這個二級索引查詢值為18的數據,并加上共享鎖,我們是只鎖定18這一行就可以了嗎? 并不是,因為是非唯一索引,這個結構中可能有多個18的存在,所以,在加鎖時會繼續(xù)往后找,找到一個不滿足條件的值(當前案例中也就是29)。此時會對18加臨鍵鎖,并對29之前的間隙加鎖。
C. 索引上的范圍查詢(唯一索引)–會訪問到不滿足條件的第一個值為止。
查詢的條件為id>=19,并添加共享鎖。 此時我們可以根據數據庫表中現(xiàn)有的數據,將數據分為三個部分:
[19]
(19,25]
(25,+∞]
所以數據庫數據在加鎖是,就是將19加了行鎖,25的臨鍵鎖(包含25及25之前的間隙),正無窮的臨鍵鎖(正無窮及之前的間隙)。
到此這篇關于深入理解MySQL的行級鎖的文章就介紹到這了,更多相關MySQL 行級鎖內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
在Windows環(huán)境下使用MySQL:實現(xiàn)自動定時備份
下面小編就為大家分享一篇在Windows環(huán)境下使用MySQL:實現(xiàn)自動定時備份的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12
MySQL獲取二維數組字符串的最后一個值的實現(xiàn)代碼
這篇文章主要介紹了MySQL獲取二維數組字符串的最后一個值的實現(xiàn),文中有詳細的代碼示例供大家參考,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2024-04-04
mysql數據損壞,如何通過ibd和frm文件批量恢復數據庫數據
這篇文章主要介紹了mysql數據損壞,如何通過ibd和frm文件批量恢復數據庫數據問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08
MySQL存儲過程中使用WHILE循環(huán)語句的方法
這篇文章主要介紹了MySQL存儲過程中使用WHILE循環(huán)語句的方法,實例分析了在MySQL中循環(huán)語句的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07

