Mysql鎖機制

541732025發表於2016-04-18

文章原創於公眾號:程式猿周先森。本平臺不定時更新,喜歡我的文章,歡迎關注我的微信公眾號。

file

鎖是計算機協調多個程式或執行緒併發訪問某一資源的機制。在資料庫中資料其實是一種供大量使用者共享的資源,所以在併發訪問時我們需要保證資料的一致性和有效性,而鎖衝突是影響資料庫併發效能最關鍵的因素之一。所以本篇文章主要討論Mysql中鎖機制的特點。Mysql的鎖機制包含多種:行鎖,表鎖,讀鎖,寫鎖等,其實就是使用不同的儲存引擎會支援不同的鎖機制。而我主要是針對InnoDB儲存引擎下的7種型別的鎖進行介紹。

InnoDB引擎鎖型別:

  • 共享/排它鎖
  • 記錄鎖
  • 間隙鎖
  • 臨鍵鎖
  • 自增鎖
  • 意向鎖
  • 插入意向鎖

MySQL中InnoDB儲存引擎與MyISAM儲存引擎鎖機制其實有兩個比較顯著的不同點:

  • InnoDB支援事務操作。
  • InnoDB預設採用行級鎖。

InnoDB鎖機制實現原理

InnoDB儲存引擎其實是通過給索引上的索引項新增鎖,也正是由於給索引項加鎖,所以只有通過索引條件查詢資料,InnoDB引擎才會選擇使用行級鎖,否則會使用表鎖。行級鎖與表級鎖本身有許多不同之處,事務的引入也帶來了一些新問題。

事務說到事務,四個最基本的特性我想大多數人再清楚不過了:

  • 原子性: 事務是一個原子操作單元,其對資料的修改,要麼全都執行,要麼全都不執行。
  • 一致性:在事務開始和完成時,資料都必須保持一致狀態。
  • 隔離性:事務處理過程中的中間狀態對外部是不可見的。
  • 永續性:事務完成之後,它對於資料的修改是永久性的。

併發的問題

併發事務處理能大大增加資料庫資源的利用率,提高資料庫系統的事務吞吐量,但併發事務處理如果沒有新增鎖存在幾個問題:

  • 更新丟失:兩個事務同時對同一個資料進行更新操作,先更新的資料會被後更新的給更換了,造成資料丟失。
  • 髒讀:兩個事務一個負責更新操作,一個負責查詢操作,更新操作更新了但是還未提交資料,這時候查詢資料會出現資料不一致現象,也就是我們經常說的髒資料。
  • 不可重複讀:有一個事務在讀取資料後的某個時間,再次讀取同樣的資料,卻發現得到資料發生改變。
  • 幻讀:第一個事務查詢資料,重複讀取相同資料,第二次檢索比第一次得到新資料,叫幻讀現象。

共享/排它鎖

這種鎖機制實際上有兩個鎖:共享鎖和排它鎖。讀取資料時會使用共享鎖,是可以並行操作的,也就是讀取資料操作是可以併發進行的。修改資料時會使用排它鎖,排它鎖與任何鎖都是互斥存在,也就是修改資料是其他操作無論讀取還是修改操作都不能併發進行。

記錄鎖

記錄鎖顧名思義封鎖記錄,例如我們查詢學號sid為1的學生資訊,使用排它鎖就會將這行記錄鎖死,所以其他事務都無法對這行資料進行操作。實際上記錄鎖是先獲取這個資料表的意向排它鎖,表示本事務有意向向這個資料表的某些資料加排它鎖,然後在獲取這行資料的排它鎖,這時候其他他事務都無法對這行資料進行操作了。那什麼是意向排它鎖呢,接下來我們看看意向鎖。

意向鎖

意向鎖之所以出現實際上是為了讓行級鎖與表級鎖共存,意向鎖實際上就是剛才所講的,本事務未來某個時刻需要對某個資料表加鎖,所以先和你宣告一下意向。意向鎖是表級鎖,一樣分為意向共享鎖與意向排它鎖,但是和共享排它鎖有一點不同是意向鎖之間是互相相容的,也就是說無論是意向排它鎖還是意向共享鎖之間都是相互相容的,但是意向鎖與排它鎖是不相容的,因為排它鎖不與其他任何鎖相相容。

間隙鎖

間隙鎖的出現其實是為了杜絕不可重複讀的情況,使用間隙鎖可以對某個欄位新增區間限制,比如我們查詢id=1的資料我們可以對id為1的資料新增間隙鎖,這樣本事務沒有結束之前,其他資料無法對id為1的資料進行更新操作,也就是可以解決不可重複讀的問題。如果將事務的隔離級別設定為讀提交,則間隙鎖無法生效。

臨鍵鎖

臨鍵鎖實際上是同時作用於索引間隙和索引記錄,也就是記錄鎖和間隙鎖的結合體。使用臨鍵鎖預設情況下是同時對索引記錄和索引間隙進行鎖定,也就是雙重鎖定,但是如果索引為唯一索引或者主鍵索引,則會使用記錄鎖只對索引本身加鎖,不會新增間隙鎖,所以說欄位有唯一值可以新增唯一索引提高效能。

插入意向鎖

插入意向鎖是作用於索引上,專門用於插入操作的鎖。這個鎖是可以多個事務共同操作的,多個事務同時操作同一個索引,在插入記錄時如果插入位置不衝突則不會互相影響插入操作。比如我們兩個事務同時進行,分別插入id為1和id為2的記錄,因為id不衝突,所以不會互相阻塞操作。

自增鎖

自增鎖很明顯是用於自增型別的操作,自增鎖是表級鎖,自增鎖的作用是為了保證資料庫的主鍵是自動遞增的。其實這個鎖主要就是用於擁有自增主鍵的資料表的插入操作,兩個事務先後執行插入操作,第二個事務的插入操作則會被阻塞,因為需要保證主鍵是遞增操作。

表鎖注意事項

剛才其實提到了,InnoDB中預設使用行級鎖,但是意向鎖這種表級鎖其實有時候更適合,比如需要在事務中更新大部分資料,這時候使用表鎖就可以提高事務的執行任務。或者說事務中涉及多個表的操作,如果出現死鎖等,就會造成大量操作回滾,所以這種情況就可以直接將所有涉及的表都新增表鎖,就可以減小出現死鎖的概率,減小資料庫的開銷。

避免死鎖的方案

死鎖其實就是兩個事務在執行過程中因為爭奪資源造成的一種互相等待的現象,這時候就成為產生了死鎖。死鎖產生的關鍵原因其實是因為兩個事務加鎖的順序不一致,然後互相持有資源不釋放又互相等待對方的資源。發生死鎖一般情況下InnoDB引擎可以自動檢測並且使一個事務回滾解決死鎖問題,但是涉及表鎖或者外部鎖時不能保證檢測到死鎖的存在,所以我們需要了解避免死鎖的方案。一般有以下幾種策略:

  • 死鎖預防:破壞導致死鎖必要條件中的任意一個就可以預防死鎖。例如,要求使用者申請資源時一次性申請所需要的全部資源,這就破壞了保持和等待條件;將資源分層,得到上一層資源後,才能夠申請下一層資源,它破壞了環路等待條件。預防通常會降低系統的效率。
  • 死鎖避免:避免是指程式在每次申請資源時判斷這些操作是否安全,例如,使用銀行家演算法。死鎖避免演算法的執行會增加系統的開銷。
  • 死鎖檢測:死鎖預防和避免都是事前措施,而死鎖的檢測則是判斷系統是否處於死鎖狀態,如果是,則執行死鎖解除策略。
  • 死鎖解除:這是與死鎖檢測結合使用的,它使用的方式就是剝奪。即將某程式所擁有的資源強行收回,分配給其他的程式。

歡迎關注公眾號:程式猿周先森。文章原創於微信公眾號,本平臺不定時更新。

相關文章