簡談Mysql的InnoDB存儲引擎中的鎖,讓你輕鬆掌握

一、InnoDB存儲引擎中的鎖

鎖,在現實生活中是爲我們想要隱藏於外界所使用的一種工具。在計算機中,是協調多個進程或縣城併發訪問某一資源的一種機制。在數據庫當中,除了傳統的計算資源(CPU、RAM、I/O等等)的爭用之外,數據也是一種供許多用戶共享訪問的資源。如何保證數據併發訪問的一致性、有效性,是所有數據庫必須解決的一個問題,鎖的衝突也是影響數據庫併發訪問性能的一個重要因素。從這一角度來說,鎖對於數據庫而言就顯得尤爲重要。

相對於其他的數據庫而言,MySQL的鎖機制比較簡單,最顯著的特點就是不同的存儲引擎支持不同的鎖機制。根據不同的存儲引擎,MySQL中鎖的特性可以大致歸納如下:

簡談Mysql的InnoDB存儲引擎中的鎖,讓你輕鬆掌握

這裏鎖的對象是事務,用來鎖定數據庫中的對象,如:表、頁、行。並且一般鎖的對象僅在事務commit或rollback後進行釋放。並且有死鎖機制。

下面我們看InnoDB存儲引擎中兩種標準的行級鎖:

  • 共享鎖(S Lock),允許事務讀一行數據

  • 排它鎖(X Lock),允許事務刪除或更新一行數據

若事務T對數據對象A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。

若事務T對數據對象A加上X鎖,事務T可以讀A也可以修改A,其他事務不能再對A加任何鎖,直到T釋放A上的鎖。

上述情況稱爲鎖不兼容。

此外,InnoDB存儲引擎還支持多粒度鎖定,這種鎖定允許事務在行級上的鎖和表級上的鎖同時存在。爲了支持在不同粒度上進行加鎖操作,InnoDB存儲引擎支持一種額外的鎖方式,稱之爲意向鎖。

所謂意向鎖,就是將要鎖定的對象分成多個層次,意向鎖意味着事務希望在更細粒度上進行加鎖。如果把上鎖的對象看成樹形結構(從根到葉爲從粗粒度到細粒度的順序),那麼對最下層的對象上鎖,必須先對他的上層節點上鎖。

舉個例子,比如事務T要對某一行R1加X鎖,必須先對R1所在的表T1加意向鎖IX(Intention X Lock)。相應的也有IS(Intetion S Lock)鎖。

剛開始我也是很懵的,不知道引入意向鎖到底是幹嘛的。後來再刷書的時候,才豁然開朗。下面我談下我的理解。

因爲引入意向鎖是用來實現多粒度鎖定的,即行鎖和表鎖同時存在。我們看看如果不引入意向鎖,怎麼判斷。

如果事務T要對錶T1加X鎖,那麼這是就必須要判斷T1表下的每一行記錄是否加了S鎖或X鎖(因爲上面提到了鎖有不兼容性)。這樣做效率無疑很低。那麼引入意向鎖之後呢?

如果事務T要對錶T1加X鎖,在這之前,已經有事務對錶T1中的行記錄R加了S鎖,那麼此時在表T1上有IS鎖,當事務T對錶T1準備加X鎖時,由於X鎖與IS鎖不兼容(關於兼容性後面會給出表格),所以事務T要等待行鎖操作完成。你看,這樣就省去了遍歷的操作,提升了鎖定父節點(本例爲表T1)的效率。

下圖就是X、S、IX、IS鎖的兼容性了:

簡談Mysql的InnoDB存儲引擎中的鎖,讓你輕鬆掌握

二、鎖的算法

InnoDB存儲引擎有3種行鎖的算法,分別是:

  • Record Lock:單個行記錄上的鎖

  • Gap Lock:間隙鎖,鎖定一個範圍,但不包含記錄本身

  • Next-Key Lock:Gap Lock+Record Lock,鎖定一個範圍,並且鎖定記錄本身。

舉例說明:
假如一個索引有10,11,13,20這四個值。那麼該索引可能被Next-Key Locking的區間爲:
(-∞,10]
(10,11]
(11,13]
(13,20]
(20,+∞)


對於Next_Key Lock,如果我們鎖定了一個行,且查詢的索引含有唯一屬性時(即有唯一索引),那麼這個時候InnoDB會將Next_Key Lock優化成Record Lock,也就是鎖定當前行,而不是鎖定當前行加一個範圍;如果我們使用的不是唯一索引鎖定一行數據,那麼此時InnoDB就會按照本來的規則鎖定一個範圍和記錄。還有需要注意的點是,當唯一索引由多個列組成時,如果查詢僅是查找其中的一個列,這時候是不會降級的。還有注意的點是,InnoDB存儲引擎還會對輔助索引的下一個鍵值區間加上gap lock(這麼做也是爲了防止幻讀)。Next_Key Lock是爲了解決數據庫出現幻讀的問題。

關於如何加鎖詳見我的這篇文章:Mysql的一致性非鎖定讀和一致性鎖定讀

有關髒讀、不可重複讀、幻讀詳見我的這篇文章淺析Mysql的隔離級別及MVCC

InnoDB存儲引擎默認的事務隔離級別是RR級別,即可重複讀。在該級別下,採用next-key locking的方式加鎖。故而可以防止幻讀現象。

舉例一下,爲什麼next-key locking 可以解決幻讀問題吧:

所謂幻讀,就是在同一事務下,連續執行兩次同樣的SQL語句可能導致不同的結果,第二次的SQL語句可能會返回之前不存在的行。

創建表t:

create table t (a int primary key);insert into t select 1;insert into t select 2;insert into t select 5;

這時有三行記錄,分別是1,2,5。

假設有如下執行序列:

簡談Mysql的InnoDB存儲引擎中的鎖,讓你輕鬆掌握

我們分析一下,會話A在時間2查詢的結果爲5,由於使用了select...for update語句,爲(2,+∞)這個範圍加了X鎖。因此任何對於這個範圍的插入都是不被允許的,由於4在這個範圍,所以不允許插入,也就避免了幻讀。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章