<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          [精選]詳細(xì)介紹MySQL中常見(jiàn)的鎖

          共 5838字,需瀏覽 12分鐘

           ·

          2021-07-04 23:43

          一、死鎖示例

          考慮下面一個(gè)MySQL死鎖的示例:

          有如下一張表:

          CREATE TABLE `test` (`id` int(20) NOT NULL,`name` varchar(20) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8

          表中有如下數(shù)據(jù):

          mysql> SELECT * FROM test;+----+------+| id | name |+----+------+|  1 | 1    ||  5 | 5    || 10 | 10   || 15 | 15   || 20 | 20   || 25 | 25   |+----+------+6 rows in set (0.00 sec)

          當(dāng)數(shù)據(jù)庫(kù)的隔離級(jí)別為Repeatable Read或Serializable時(shí),我們來(lái)看這樣的兩個(gè)并發(fā)事務(wù)(場(chǎng)景一):


          上面兩個(gè)并發(fā)事務(wù)一定會(huì)發(fā)生死鎖(這里之所以限定RR和Serializable兩個(gè)隔離級(jí)別,是因?yàn)橹挥羞@兩個(gè)級(jí)別下才會(huì)有間隙鎖/臨鍵鎖,而這是導(dǎo)致死鎖的根本原因,后面會(huì)詳細(xì)分析)。


          我們?cè)賮?lái)看另外一個(gè)并發(fā)場(chǎng)景(場(chǎng)景二):

          在這個(gè)并發(fā)場(chǎng)景下,兩個(gè)事務(wù)均能成功提交,而不會(huì)有死鎖。


          在上面的示例中,我們發(fā)現(xiàn),select ... for update雖然可以用于解決數(shù)據(jù)庫(kù)的并發(fā)操作,但在實(shí)際項(xiàng)目中卻不建議使用,原因是當(dāng)查詢(xún)條件對(duì)應(yīng)的記錄不存在時(shí),很容易造成死鎖。而造成死鎖的原因和MySQL的鎖機(jī)制有關(guān)。本文將詳細(xì)介紹常見(jiàn)的七種鎖機(jī)制,了解了這些鎖機(jī)制之后就能理解造成場(chǎng)景一死鎖的根本原因以及場(chǎng)景一和場(chǎng)景二差異的原因。


          二、MySQL的七種鎖

          1. 行鎖(Record Locks)

          2. 間隙鎖(Gap Locks)

          3. 臨鍵鎖(Next-key Locks)

          4. 共享鎖/排他鎖(Shared and Exclusive Locks)

          5. 意向共享鎖/意向排他鎖(Intention Shared and Exclusive Locks)

          6. 插入意向鎖(Insert Intention Locks)

          7. 自增鎖(Auto-inc Locks)

          實(shí)際上,MySQL官網(wǎng)中還提到了一種預(yù)測(cè)鎖,這種鎖主要用于存儲(chǔ)了空間數(shù)據(jù)的空間索引,本文暫不討論。


          1、行鎖

          這MySQL的官方文檔中有以下描述:

          A record lock is a lock on an index record. Record locks always lock index records, even if a table is defined with no indexes. For such cases, InnoDB creates a hidden clustered index and uses this index for record locking.

          這句話(huà)說(shuō)明行鎖一定是作用在索引上的。


          2、間隙鎖

          在MySQL的官方文檔中有以下描述:

          A gap lock is a lock on a gap between index records, or a lock on the gap before the first or after the last index record。

          這句話(huà)表明間隙鎖一定是開(kāi)區(qū)間,比如(3,5)或者。在MySQL官網(wǎng)上還有一段非常關(guān)鍵的描述:

          Gap locks in InnoDB are “purely inhibitive”, which means that their only purpose is to prevent other transactions from inserting to the gap. Gap locks can co-exist. A gap lock taken by one transaction does not prevent another transaction from taking a gap lock on the same gap. There is no difference between shared and exclusive gap locks. They do not conflict with each other, and they perform the same function.

          這段話(huà)表明間隙鎖在本質(zhì)上是不區(qū)分共享間隙鎖或互斥間隙鎖的,而且間隙鎖是不互斥的,即兩個(gè)事務(wù)可以同時(shí)持有包含共同間隙的間隙鎖。這里的共同間隙包括兩種場(chǎng)景:其一是兩個(gè)間隙鎖的間隙區(qū)間完全一樣;其二是一個(gè)間隙鎖包含的間隙區(qū)間是另一個(gè)間隙鎖包含間隙區(qū)間的子集。間隙鎖本質(zhì)上是用于阻止其他事務(wù)在該間隙內(nèi)插入新記錄,而自身事務(wù)是允許在該間隙內(nèi)插入數(shù)據(jù)的。也就是說(shuō)間隙鎖的應(yīng)用場(chǎng)景包括并發(fā)讀取、并發(fā)更新、并發(fā)刪除和并發(fā)插入


          在MySQL官網(wǎng)上關(guān)于間隙鎖還有一段重要描述:

          Gap locking can be disabled explicitly. This occurs if you change the transaction isolation level to READ COMMITTED. Under these circumstances, gap locking is disabled for searches and index scans and is used only for foreign-key constraint checking and duplicate-key checking.

          這段話(huà)表明,在RU和RC兩種隔離級(jí)別下,即使你使用select ... in share mode或select ... for update,也無(wú)法防止幻讀(讀后寫(xiě)的場(chǎng)景)。因?yàn)檫@兩種隔離級(jí)別下只會(huì)有行鎖,而不會(huì)有間隙鎖。這也是為什么示例中要規(guī)定隔離級(jí)別為RR的原因。


          3、臨鍵鎖

          在MySQL的官方文檔中有以下描述:

          A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index record.

          這句話(huà)表明臨鍵鎖是行鎖+間隙鎖,即臨鍵鎖是是一個(gè)左開(kāi)右閉的區(qū)間,比如(3,5]


          在MySQL的官方文檔中還有以下重要描述:

          By default, InnoDB operates in REPEATABLE READ transaction isolation level. In this case, InnoDB uses next-key locks for searches and index scans, which prevents phantom rows.

          個(gè)人覺(jué)得這段話(huà)描述得不夠好,很容易引起誤解。這里更正如下:InnoDB的默認(rèn)事務(wù)隔離級(jí)別是RR,在這種級(jí)別下,如果你使用select ... in share mode或者select ... for update語(yǔ)句,那么InnoDB會(huì)使用臨鍵鎖,因而可以防止幻讀;但即使你的隔離級(jí)別是RR,如果你這是使用普通的select語(yǔ)句,那么InnoDB將是快照讀,不會(huì)使用任何鎖,因而還是無(wú)法防止幻讀。


          4、共享鎖/排他鎖

          在MySQL的官方文檔中有以下描述:

          InnoDB implements standard row-level locking where there are two types of locks, shared (S) locks and exclusive (X) locks。

          A shared (S) lock permits the transaction that holds the lock to read a row.

          An exclusive (X) lock permits the transaction that holds the lock to update or delete a row.

          這段話(huà)明確說(shuō)名了共享鎖/排他鎖都只是行鎖,與間隙鎖無(wú)關(guān),這一點(diǎn)很重要,后面還會(huì)強(qiáng)調(diào)這一點(diǎn)。其中共享鎖是一個(gè)事務(wù)并發(fā)讀取某一行記錄所需要持有的鎖,比如select ... in share mode;排他鎖是一個(gè)事務(wù)并發(fā)更新或刪除某一行記錄所需要持有的鎖,比如select ... for update。
          不過(guò)這里需要重點(diǎn)說(shuō)明的是,盡管共享鎖/排他鎖是行鎖,與間隙鎖無(wú)關(guān),但一個(gè)事務(wù)在請(qǐng)求共享鎖/排他鎖時(shí),獲取到的結(jié)果卻可能是行鎖,也可能是間隙鎖,也可能是臨鍵鎖,這取決于數(shù)據(jù)庫(kù)的隔離級(jí)別以及查詢(xún)的數(shù)據(jù)是否存在。關(guān)于這一點(diǎn),后面分析場(chǎng)景一和場(chǎng)景二的時(shí)候還會(huì)提到。


          5、意向共享鎖/意向排他鎖

          在MySQL的官方文檔中有以下描述:

          Intention locks are table-level locks that indicate which type of lock (shared or exclusive) a transaction requires later for a row in a table。


          The intention locking protocol is as follows:

          • Before a transaction can acquire a shared lock on a row in a table, it must first acquire an IS lock or stronger on the table.

          • Before a transaction can acquire an exclusive lock on a row in a table, it must first acquire an IX lock on the table.


          這段話(huà)說(shuō)明意向共享鎖/意向排他鎖屬于表鎖,且取得意向共享鎖/意向排他鎖是取得共享鎖/排他鎖的前置條件。


          共享鎖/排他鎖與意向共享鎖/意向排他鎖的兼容性關(guān)系:

          這里需要重點(diǎn)關(guān)注的是IX鎖和IX鎖是相互兼容的,這是導(dǎo)致上面場(chǎng)景一發(fā)生死鎖的前置條件,后面會(huì)對(duì)死鎖原因進(jìn)行詳細(xì)分析。


          6、插入意向鎖(IIX)

          在MySQL的官方文檔中有以下重要描述:

          An insert intention lock is a type of gap lock set by INSERT operations prior to row insertion. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap. Suppose that there are index records with values of 4 and 7. Separate transactions that attempt to insert values of 5 and 6, respectively, each lock the gap between 4 and 7 with insert intention locks prior to obtaining the exclusive lock on the inserted row, but do not block each other because the rows are nonconflicting.


          這段話(huà)表明盡管插入意向鎖是一種特殊的間隙鎖,但不同于間隙鎖的是,該鎖只用于并發(fā)插入操作。如果說(shuō)間隙鎖鎖住的是一個(gè)區(qū)間,那么插入意向鎖鎖住的就是一個(gè)點(diǎn)。因而從這個(gè)角度來(lái)說(shuō),插入意向鎖確實(shí)是一種特殊的間隙鎖。與間隙鎖的另一個(gè)非常重要的差別是:盡管插入意向鎖也屬于間隙鎖,但兩個(gè)事務(wù)卻不能在同一時(shí)間內(nèi)一個(gè)擁有間隙鎖,另一個(gè)擁有該間隙區(qū)間內(nèi)的插入意向鎖(當(dāng)然,插入意向鎖如果不在間隙鎖區(qū)間內(nèi)則是可以的)。這里我們?cè)倩仡櫼幌鹿蚕礞i和排他鎖:共享鎖用于讀取操作,而排他鎖是用于更新或刪除操作。也就是說(shuō)插入意向鎖、共享鎖和排他鎖涵蓋了常用的增刪改查四個(gè)動(dòng)作。


          7、示例分析

          到此為止,我們介紹了MySQL常用的七種鎖的前六種,理解了這六種鎖之后,才能很好地分析和理解開(kāi)頭給出的兩個(gè)場(chǎng)景。我們先來(lái)分析場(chǎng)景一:

          在場(chǎng)景一中,因?yàn)镮X鎖是表鎖且IX鎖之間是兼容的,因而事務(wù)一和事務(wù)二都能同時(shí)獲取到IX鎖和間隙鎖。另外,需要說(shuō)明的是,因?yàn)槲覀兊母綦x級(jí)別是RR,且在請(qǐng)求X鎖的時(shí)候,查詢(xún)的對(duì)應(yīng)記錄都不存在,因而返回的都是間隙鎖。接著事務(wù)一請(qǐng)求插入意向鎖,這時(shí)發(fā)現(xiàn)事務(wù)二已經(jīng)獲取了一個(gè)區(qū)間間隙鎖,而且事務(wù)一請(qǐng)求的插入點(diǎn)在事務(wù)二的間隙鎖區(qū)間內(nèi),因而只能等待事務(wù)二釋放間隙鎖。這個(gè)時(shí)候事務(wù)二也請(qǐng)求插入意向鎖,該插入點(diǎn)同樣位于事務(wù)一已經(jīng)獲取的間隙鎖的區(qū)間內(nèi),因而也不能獲取成功,不過(guò)這個(gè)時(shí)候,MySQL已經(jīng)檢查到了死鎖,于是事務(wù)二被回滾,事務(wù)一提交成功。


          分析并理解了場(chǎng)景一,那場(chǎng)景二理解起來(lái)就會(huì)簡(jiǎn)單多了:

          場(chǎng)景二中,兩個(gè)間隙鎖沒(méi)有交集,而各自獲取的插入意向鎖也不是同一個(gè)點(diǎn),因而都能執(zhí)行成功。

          往期精選

          手把手教你分析Mysql死鎖問(wèn)題 [建議收藏]

          MySQL 三萬(wàn)字精華總結(jié) —鎖機(jī)制和性能調(diào)優(yōu)

          Mysql之鎖、事務(wù)絕版詳解---干貨!

          MySQL 三萬(wàn)字精華總結(jié) + 面試100 問(wèn)

          MySQL中count(*)、count(主鍵id)、count(字段)和count(1)那種效率更高?

          瀏覽 51
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大香蕉久久伊人网 | 久久免费成人视频 | 国产精品卡_卡2卡3卡4一商战-信息网 | 影音先锋中文资源网 | 久久久久久99精品无码 |