溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MySQL中有哪些鎖

發(fā)布時間:2021-12-04 14:07:59 來源:億速云 閱讀:218 作者:iii 欄目:數(shù)據(jù)庫

本篇內(nèi)容介紹了“MySQL中有哪些鎖”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

普通鎖

InnoDB 實現(xiàn)了標(biāo)準(zhǔn)行級鎖,而行級鎖有兩種類型:

  • 共享鎖(shared lock,以下將會簡稱為 S 鎖):意在共享。也就是允許多個事務(wù)共同持有一個記錄的共享鎖,該鎖主要用于讀取操作。

  • 排他鎖(exclusive lock,以下將會簡稱為 X 鎖):意在排斥。只能允許一個事務(wù)持有一個記錄的排他鎖,該鎖主要用于更新和刪除操作。

如果你有了解過 Java 中的 JUC 包,那么你就會發(fā)現(xiàn)這有點像 JUC 中的讀寫鎖  ReentrantReadWriteLock。它們的目的都是為了提高讀取操作的并發(fā)性。

如果有一個事務(wù) T1 持有行 r 的 S 鎖,并且同時有另一個事務(wù) T2 想要獲取行 r 中的鎖,T2 獲取不同的鎖將會有如下的情況發(fā)生:

  • 假如 T2 想要獲取行 r 的 S 鎖,那么 T2 將會立刻得到該鎖。

  • 假如 T2 想要獲取行 r 的 X 鎖,那么 T2 則會被阻塞,直到 T1 釋放了行 r 的 S 鎖。

如果有一個事務(wù) T1 持有性 r 的 X 鎖,并且同時有另一個事務(wù) T2 想要獲取行 r 中的鎖,不管 T2 獲取什么鎖都會被阻塞。

X 鎖與 S 鎖的兼容性如下圖所示:

MySQL中有哪些鎖

最左邊是持有的鎖,最上面是想要申請的鎖。從圖中可以看出,只要跟 X 鎖相關(guān)的,都會沖突,也就是會造成阻塞。

意向鎖

InnoDB 允許多種粒度的鎖共存,所以會有表鎖和行鎖共存的情況。為了讓多種粒度的鎖可以共存,InnoDB  使用了意向鎖。意向鎖是表級鎖,它是為了表明有一個事務(wù)正在持有鎖或者打算申請一個鎖。

意向鎖有兩種類型:

  • 共享意向鎖(intention shared lock,以下簡稱 IS):表示事務(wù)持有表中行的共享鎖或者打算獲取行的共享鎖。

  • 共享排他鎖(intention exclusive lock,以下簡稱 IX):表示事務(wù)持有表中行的排他鎖或者打算獲取行的排他鎖。

IS 和 IX 只是為了表達出一種意圖,它們除了全表請求之外,不會阻塞任何操作。它們的主要目的只是為了表示持有一個行鎖,或者打算獲取行鎖。

意向鎖的使用規(guī)則如下:

  • 事務(wù)在獲取表中的共享行鎖時,需要先獲取表中的 IS 鎖或者等級更高的鎖。

  • 事務(wù)在獲取表中的排他行鎖時,需要先獲取表中的 IX 鎖。

這里有一個很重要的點:就是只有獲取表中的行鎖時,才會需要先申請意向鎖。 如果是執(zhí)行 ALTER TABLE  等需要鎖定整個表的語句,是不需要申請意向鎖的,可以直接去申請表級 X 鎖。

表級別下的X鎖、S鎖、IS 鎖和 IX 鎖的兼容性如下:

MySQL中有哪些鎖

注意:這里的 X 鎖、S 鎖說的也是表級鎖,不要理所當(dāng)然的想成了行級鎖。

為什么會有意向鎖的出現(xiàn)呢?我們考慮如下場景(假設(shè)不存在意向鎖):

一個事務(wù) A 想要修改表 t 中的行 r,所以 A 獲取行 r 的 X 鎖,事r務(wù) A 現(xiàn)在持有一個行鎖。此時,有一個事務(wù) B 想要使用 ALTER  TABLE 語句修改表 t 的結(jié)構(gòu),該語句首先需要獲取表 t 的 X 鎖,但是此時事務(wù) B  并不知道表中是否有行被鎖住,所以它只能一行一行去遍歷,然后把遍歷的行也鎖住,直到發(fā)現(xiàn)表中沒有行在之前已經(jīng)被鎖住,現(xiàn)在它就可以修改表的結(jié)構(gòu)了。但是它發(fā)現(xiàn)表中已經(jīng)存在一些行被鎖住,那么它就不能修改表結(jié)構(gòu),需要等這些鎖都釋放。

MySQL中有哪些鎖

這里有一個大問題,最壞的情況下,需要遍歷所有的行才能知道是否有行被鎖住,這是非常消耗性能的,而意向鎖就可以解決這個問題。我們現(xiàn)在再來考慮相同場景下,意向鎖如何解決這個問題:

一個事務(wù) A 想要修改表 t 中的行 r,A 首先需要獲取表 t 的 IX 鎖,然后成功獲取 IX 鎖之后,再去申請行 r 的 X 鎖,申請成功之后,事務(wù)  A 此時就持有兩個鎖,分別是表 t 的 IX 鎖和行 r 的 X 鎖。此時,有一個事務(wù) B 想要使用 ALTER TABLE 語句修改表 t  的結(jié)構(gòu),該語句需要獲取表 t 的 X 鎖,事務(wù) B 可以查看表 t 上是否存在鎖來判斷表中的行是否被上鎖,當(dāng)發(fā)現(xiàn)表 t 上存在 IX 鎖,事務(wù) B  就會被阻塞,因為它知道表中已經(jīng)有行被鎖定,所以無法申請到表 t 的 X 鎖。

MySQL中有哪些鎖

我們看上面的兼容性表,也得知表級的 IX 鎖和表級的 X 鎖是沖突的,所以剛剛好對應(yīng)上這個場景。

記錄鎖

記錄鎖是對索引記錄的鎖定,換句話說就是,記錄鎖只會鎖定索引。每一個表必定會有一個主鍵索引(用戶定義的主鍵、唯一索引、隱式生成),而該主鍵索引中的非葉子節(jié)點中的記錄就是使用該記錄鎖進行鎖定。

假設(shè)執(zhí)行語句:select * from user where id = 10 for update;

如果 id 是 user 表中的主鍵,那么在主鍵索引中,id 為 10  的記錄就會被鎖定。并且其他事務(wù)想要更新、刪除此條記錄都會被阻塞,只有等該記錄中的記錄鎖被釋放之后,才可以執(zhí)行其他操作。

MySQL中有哪些鎖

除了主鍵索引之外,InnoDB  中還會有二級索引。二級索引跟主鍵索引一樣,在使用二級索引作為查詢條件時,會將符合條件的二級索引的記錄使用記錄鎖進行鎖定,然后再回表將對應(yīng)的主鍵索引也使用記錄鎖進行鎖定。

假設(shè)執(zhí)行語句:select * from user where name = 'c' for update;

如果 id 是 user 表中的主鍵,name 是 user 表中的二級索引。則會先將二級索引下的 name = ‘c’  的索引鎖定,然后再進行回表將主鍵索引為 9 的主鍵索引鎖定。

MySQL中有哪些鎖

間隙鎖

間隙鎖(簡稱為  Gap)是對索引記錄之間的間隙的鎖定,或者是對第一條索引記錄之前的間隙和對最后一條記錄之后的間隙的鎖。間隙鎖是防止幻讀的主要手段之一,幻讀是同一個事務(wù)在不同的時間執(zhí)行相同的查詢語句,得出的結(jié)果集不同。那么間隙鎖是如何防止幻讀的呢?實際上就是通過鎖定指定的間隙,使得這些間隙無法插入新的記錄,從而防止了數(shù)據(jù)的增長。

假設(shè)我們執(zhí)行此條語句:select * from user where id > 5 and id < 9 for update;

由于間隙鎖的存在,其他事務(wù)如果想要插入 id 在 5 和 9 之間的記錄是無法成功的,會被阻塞,直到間隙鎖釋放。比如想要插入 id 為 6  的記錄,就會阻塞,如下圖所示(省略部分無關(guān)的字段)。間隙鎖跨越的間隙可能為一個值、多個值、甚至為空值。

MySQL中有哪些鎖

通過上圖我們可以知道:

  • (5, 7]:id 為 5 的索引記錄與 id 為 7 的索引記錄之間的間隙被間隙鎖鎖定了

  • (7, 9]:id 為 7 的索引記錄與 id 為 9 的索引記錄之間的間隙被間隙鎖鎖定了

因為這兩個間隙被間隙鎖鎖定了,所以在這兩個間隙之間的記錄是無法插入,只有等間隙鎖釋放之后才可以插入。我們還要注意到,id 為 7  的記錄是被記錄鎖鎖定的,所以在 id 為 7 的記錄上執(zhí)行更新、刪除操作時會被阻塞的。

我們上面還說到,間隙鎖還在第一條記錄的前面和最后一條記錄的后面加鎖,我們來看看這是什么情況。

假設(shè)我們執(zhí)行此條語句:select * from user for update;

因為該語句沒有使用索引,所以會進行全表掃描。將掃描到的每一條記錄都加上記錄鎖,并且將所有的間隙也加間隙鎖。最終的加鎖情況如下圖所示(省略部分無關(guān)的字段):

MySQL中有哪些鎖

每個表中都會存在兩個隱式記錄:最小記錄(infimum),最大記錄(supermum)

我們通過上圖,可以得出鎖定的區(qū)間如下:

  • (-&infin;, 5]

  • (5, 7]

  • (7, 9]

  • (9, 10]

  • (10, 12]

  • (12, +&infin;)

并且所有的記錄都被記錄鎖鎖定。這個看起來就像是一個表鎖,因為對該表的任何操作(快照讀除外),都會被阻塞。

但是,間隙鎖并不是在任何情況下都會使用,它在以下情況并不會使用:

隔離級別為 RC、RU。

使用唯一索引進行等值比較獲取一條索引記錄。這是因為唯一索引進行等值比較只能獲取一條記錄,不會出現(xiàn)多條記錄的情況,那么也就不會出現(xiàn)多次讀取出現(xiàn)不一致的情況。

間隙鎖的主要目的是阻止事務(wù)往間隙中插入記錄,并且間隙鎖之間是可以共存的,多個事務(wù)可以同時獲取得到相同間隙的鎖。共享間隙鎖和排他間隙鎖之間并沒有區(qū)別,它們是完全一樣的東西。

Next-Key 鎖

Next-Key 鎖并不是一個難以理解的東西,它本質(zhì)上就是索引記錄上的記錄鎖和索引記錄之間的間隙鎖的結(jié)合。

InnoDB 在查找和掃描表的時候,會將掃描到的記錄都加上記錄鎖,記錄鎖有可能是共享鎖或者是排他鎖。因此,行級鎖實際上是索引記錄鎖。

在間隙鎖的兩個例子中的第二個例子,它實際上就是 Next-Key 鎖,因為每一個括號括起來的內(nèi)存包括一個索引記錄鎖和一個間隙鎖,而 這完美符合  Next-Key 的定義。

在默認的 REPEATABLE READ 隔離級別下,InnoDB 在查找和掃描索引時,都會使用 Next-Key 鎖,以此來防止幻讀的發(fā)生。

插入意向鎖

插入意向鎖(簡稱為 II  Gap)是一種特殊的間隙鎖,只有在插入記錄的時候才會使用,這個鎖表示插入的意向。它與上面說到的表級意向鎖是完全不同的,插入意向鎖是屬于行級鎖,并且互相之間是兼容的,互不沖突,所以多個事務(wù)可以同時獲取到相同間隙的  II Gap 鎖。

官方示例:

假設(shè)有索引記錄,其值分別為4和7,單獨的事務(wù)分別嘗試插入值5和6,在獲得插入行的排他鎖之前,每個事務(wù)都使用插入意圖鎖來鎖定4和7之間的間隙,但不要互相阻塞,因為行是無沖突的。

插入意向鎖只會和間隙鎖和 Next-Key  鎖沖突。因為間隙鎖的主要作用是防止幻讀的發(fā)生,而在插入操作執(zhí)行前需要獲取到插入意向鎖,而插入意向鎖和間隙鎖之間是沖突的,可以阻塞插入操作,所以間隙鎖可以防止幻讀的發(fā)生。

AUTO-INC 鎖

AUTO-INC 鎖又稱為自增鎖(簡稱 AI 鎖)。它是特殊的表鎖,在插入數(shù)據(jù)到具有 AUTO_INCREMENT  列的表時使用。當(dāng)插入數(shù)據(jù)的表中有自增列時,數(shù)據(jù)庫需要自動生成自增值,在生成之前,它會先獲取到相關(guān)表的 AUTO-INC  鎖。其他事務(wù)的插入操作將會被阻塞,這樣可以保證自增值的唯一性。

AUTO-INC 鎖具有如下特點:

  • 每一張表都具有它自己的 AUTO-INC 鎖,互相之間不兼容。

  • 不遵循二段鎖協(xié)議,它并不是在事務(wù)提交時釋放,而是在 insert 語句執(zhí)行完成之后就釋放,提高了并發(fā)插入的性能。

  • 自增值一旦分配了就會加一,即使回滾了,自增值也不會減一,而是繼續(xù)使用下一個值,所以自增值有可能不是連續(xù)的。

因為在插入時會使用到該表鎖,所以必然會造成并發(fā)插入性能的下降。因此 InooDB 提供了一個 innodb_autoinc_lock_mode  配置項用于控制自增鎖的算法,該配置項可以使用戶選擇如何在可預(yù)測的自動增量值序列與插入操作的最大并發(fā)性之間進行權(quán)衡。

該配置有三個可選項:

0:使用傳統(tǒng)的鎖定模式,并發(fā)性能最差。

1:默認采用的模式。

2:并發(fā)性能最高,但是不能保證同一條 insert 語句內(nèi)的自增值是連續(xù)的。

想要了解更多關(guān)于此配置的內(nèi)容可以查看 MySQL 的這篇文檔。

總結(jié)

InnoDB 的四種行鎖的兼容性,如下表所示:

MySQL中有哪些鎖

note: 第一列表示已經(jīng)持有的鎖,第一行表示要獲取的鎖。

從表中可以得出結(jié)論:

插入意向鎖不影響其他事務(wù)獲取其他的鎖。

插入意向鎖會受到 Gap 鎖和 Next-Key 鎖的影響。一個事務(wù)想要獲取指定間隙的插入意向鎖,那么該間隙中的 Gap 鎖和 Next-Key  鎖必須沒有被其他事務(wù)持有,否則,將會被阻塞。

如果,我們除去插入意向鎖的影響,那么兼容性表格如下:

MySQL中有哪些鎖

從表中我們可以得出以下結(jié)論:

當(dāng)兩個事務(wù)的鎖都涉及到記錄鎖,那么將會沖突。

間隙鎖與其他鎖(不包括插入意向鎖)都不會產(chǎn)生沖突。

“MySQL中有哪些鎖”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI