秒懂INNODB的鎖

今天咱們來聊聊MySQL中InnoDB存儲引擎的鎖。算法

鎖是數據庫系統系統區別於文件系統的一個關鍵特性。數據庫

lock和 latch

latch

latch在MySQL中是用來保證併發多線程操做操做臨界資源的,鎖定的對象線程,是和我們使用的Java等傳統語言中的鎖意義相近,並且沒有死鎖檢測的機制。bash

lock

lock是MySQL中在事務中使用的,鎖定的對象是事務,來鎖定數據庫中表、頁、行;一般只有在事務commit或者rollback後進行釋放。lock是有死鎖機制的,當出現死鎖時,lock有死鎖機制來解決死鎖問題:超時時間(參數innodb_lock_wait_timeout)、wait-for graph微信

咱們一般講的MySQL的「鎖」,通常就是說的lock。網絡

如下就是InnoDB中「鎖」的大分類:多線程

lock的種類

MySQL Lock大致上能夠分爲:表鎖、行鎖、意向鎖三種。併發

共享/排他鎖

行鎖分爲:S LockX LockS Lock :讀鎖;X Lock:寫鎖。 兩鎖之間的兼容性以下。ui

X         S
X     不兼容     不兼容
S     不兼容     兼容

複製代碼

簡單總結爲:讀鎖能夠讀,讀鎖不可寫;寫鎖不可讀也tm不可寫。spa

意向鎖

InnoDB支持多粒度的鎖,即:容許表鎖和行鎖同時存在。 可是,假如表鎖覆蓋了行鎖的數據,因此表鎖和行鎖也會產生衝突。如:線程

trx1 BEGI

trx1 給 T1 加X鎖修改數據。

trx2 BEGIN

trx2 給 T1 加表鎖修改表結構
複製代碼

這樣,表鎖和行鎖之間就產生了衝突,爲了解決這種表鎖和行鎖共存的問題,就產生了意向鎖這個東西。 意向鎖:從字面意思也很好理解,就是提早代表一個「意向」。

意向鎖分爲:

  • 意向共享鎖。它預示着,事務有意向對錶中的"某些行"加S鎖。select xxxx lock in share mode,要設置IS鎖。
  • 意向排他鎖。它預示着,事務有意向表中的「某些行」加X鎖。select xxx for update,要設置IX鎖。

但意向鎖僅僅是代表意向,它其實很是弱,意向鎖之間能夠相互並行,並非排斥的: 意向鎖之間的兼容性問題:

IS     IX

IS   兼容    兼容

IX   兼容    兼容 
複製代碼

可是,意向鎖能夠和行鎖互斥。

S                X

IS     兼容           互斥不兼容

IX    互斥不兼容        互斥不兼容

複製代碼

因而,上述現象就變爲了:

trx1 BEGIN

trx1 給 T1 先加IX ,而後在某一行記錄加X鎖。

trx2 BEGIN

trx2 給 T1 加表鎖(事務被阻塞,等待加鎖成功)

trx2 修改表結構
複製代碼

主鍵自增鎖

自增鎖(auto-inc Locks)是一種特殊的表級鎖,專門針對事務插入AUTO_INCREMENT類型的列,每每就是主鍵列。能夠保證主鍵的值自增是「原子操做」,不會出現一致性、惟一性問題。

行鎖的具體分類

InnoDB存儲引擎有以上3種行鎖算法。以上3種,都是實如今索引上的。

記錄鎖(Record Lock)

記錄鎖(Record Lock)老是會去鎖住索引記錄。 假如沒有任何一個索引,那麼InnoDB會鎖住隱形建立的那個主鍵。

注意:這裏鎖的是索引,不必定只是主鍵索引哦,還多是二級普通索引。

間隙鎖(Gap Lock)

顧名思義,它會封鎖索引記錄中的「縫隙」,讓制其餘事務在「縫隙」中插入數據。 它鎖定的是一個不包含索引自己的範圍。

例如如下索引數據:

間隙鎖(Gap Lock)能夠鎖的將是如下範圍

具體的範圍還要根據查詢條件不一樣而定。 間隙鎖開啓的事務隔離級別是 Repeatable Read,若是把數據庫事務級別降爲Read Committed(默認是 Repeatable Read),間隙鎖則會自動失效。

臨鍵鎖(Next-Key Lock)

Next-Key Lock能夠說是記錄鎖(Record Lock)和間隙鎖(Gap Lock)的組合,既封鎖了"縫隙",又封鎖了索引自己。

仍是上面的索引數據:

臨鍵鎖(Next-Key Lock)鎖住的範圍將是:

Next-key Lock在索引具備惟一性的時候,例如主鍵索引的數據,將會降級爲記錄鎖(Read Lock),以增長併發性。 例如:

T1                                     T2
        BEGIN;                   |            
   select * From T               |           
   where id = 5 for update       |
---------------------------------------------------------------
                                 |            BEGIN; 
                                 |          Insert into t (4, xx);
---------------------------------------------------------------              
                                 |          COMMIT
                                 |             
----------------------------------------------------------------
     COMMIT                      |                            
                                 |
                                 |
-----------------------------------------------------------------
複製代碼

以上狀況,就會把Next-key Lock降級爲記錄鎖(Read Lock)

再談不可重複讀(No Reaptable Read)和幻讀(Phantom Problem)

有些很權威的書中認爲這倆是同一個概念,例如:<<MySQL技術內幕 InnoDB存儲引擎>>。 可是就目前網絡上的衆多總結和我的見解,認爲區別以下:

不可重複讀:修改。在同一個事務中,主要是說屢次讀取一條記錄, 發現該記錄中某些列值被修改過。 幻讀:增長或者刪除。在同一個事務中,同一條徹底相同的查詢語句返回的結果集行數不一樣。

參考:stackoverflow.com/questions/1…

認真的說,多版本併發控制 MVCC(讀)和 臨鍵鎖 Next-Key Lock(寫)共同解決了幻讀問題。

關於MVCC的原理,就是每份數據會有快照,事務中讀取數據(簡單的select xxx fromselect xx from xx for update或者select xx from xxx in share mode不行)的時候,若是數據被鎖住了,就讀之前留下的快照數據。在此不過多贅述了。

如下爲多版本併發控制原理圖

MVCC只在Read CommittedRepeatable Read下會開啓。可是在這兩種隔離級別下對於快照指定的數據定義不一樣。

Read Committed下,MVCC讀取的是被鎖定數據的最新的一份數據。 在Repeatable Read下,MVCC讀取的是事務剛開始時候的數據。

更多精彩內容,請關注個人微信公衆號 互聯網技術窩 或者加微信共同探討交流:

相關文章
相關標籤/搜索