Mysql鎖機制簡單瞭解一下

Guide哥發表於2018-06-07

歷史文章推薦:

可能是最漂亮的Spring事務管理詳解

面試中關於Java虛擬機器(jvm)的問題看這篇就夠了

Java NIO 概覽

關於分散式計算的一些概念

一 鎖分類(按照鎖的粒度分類)

Mysql為了解決併發、資料安全的問題,使用了鎖機制。

可以按照鎖的粒度把資料庫鎖分為表級鎖和行級鎖。

  • 表級鎖

    Mysql中鎖定 粒度最大 的一種鎖,對當前操作的整張表加鎖,實現簡單 ,資源消耗也比較少,加鎖快,不會出現死鎖 。其鎖定粒度最大,觸發鎖衝突的概率最高,併發度最低,MyISAM和 InnoDB引擎都支援表級鎖。

  • 行級鎖

    Mysql中鎖定 粒度最小 的一種鎖,只針對當前操作的行進行加鎖。 行級鎖能大大減少資料庫操作的衝突。其加鎖粒度最小,併發度高,但加鎖的開銷也最大,加鎖慢,會出現死鎖。 InnoDB支援的行級鎖,包括如下幾種。

    • Record Lock: 對索引項加鎖,鎖定符合條件的行。其他事務不能修改和刪除加鎖項;
    • Gap Lock: 對索引項之間的“間隙”加鎖,鎖定記錄的範圍(對第一條記錄前的間隙或最後一條將記錄後的間隙加鎖),不包含索引項本身。其他事務不能在鎖範圍內插入資料,這樣就防止了別的事務新增幻影行。
    • Next-key Lock: 鎖定索引項本身和索引範圍。即Record Lock和Gap Lock的結合。可解決幻讀問題。

雖然使用行級索具有粒度小、併發度高等特點,但是表級鎖有時候也是非常必要的

  • 事務更新大表中的大部分資料直接使用表級鎖效率更高;
  • 事務比較複雜,使用行級索很可能引起死鎖導致回滾。

二 鎖分類(按照是否可寫分類)

表級鎖和行級鎖可以進一步劃分為共享鎖(s)和排他鎖(X)。

  • 共享鎖(s)

    共享鎖(Share Locks,簡記為S)又被稱為讀鎖,其他使用者可以併發讀取資料,但任何事務都不能獲取資料上的排他鎖,直到已釋放所有共享鎖。

    共享鎖(S鎖)又稱為讀鎖,若事務T對資料物件A加上S鎖,則事務T只能讀A;其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這就保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。

  • 排他鎖(X):

    排它鎖((Exclusive lock,簡記為X鎖))又稱為寫鎖,若事務T對資料物件A加上X鎖,則只允許T讀取和修改A,其它任何事務都不能再對A加任何型別的鎖,直到T釋放A上的鎖。它防止任何其它事務獲取資源上的鎖,直到在事務的末尾將資源上的原始鎖釋放為止。在更新操作(INSERT、UPDATE 或 DELETE)過程中始終應用排它鎖。

兩者之間的區別:

  1. 共享鎖(S鎖):如果事務T對資料A加上共享鎖後,則其他事務只能對A再加共享鎖,不 能加排他鎖。獲取共享鎖的事務只能讀資料,不能修改資料。

    排他鎖(X鎖):如果事務T對資料A加上排他鎖後,則其他事務不能再對A加任任何型別的封鎖。獲取排他鎖的事務既能讀資料,又能修改資料。

  2. 共享鎖下其它使用者可以併發讀取,查詢資料。但不能修改,增加,刪除資料。資源共享.

三 另外兩個表級鎖:IS和IX

當一個事務需要給自己需要的某個資源加鎖的時候,如果遇到一個共享鎖正鎖定著自己需要的資源的時候,自己可以再加一個共享鎖,不過不能加排他鎖。但是,如果遇到自己需要鎖定的資源已經被一個排他鎖佔有之後,則只能等待該鎖定釋放資源之後自己才能獲取鎖定資源並新增自己的鎖定。而意向鎖的作用就是當一個事務在需要獲取資源鎖定的時候,如果遇到自己需要的資源已經被排他鎖佔用的時候,該事務可以需要鎖定行的表上面新增一個合適的意向鎖。如果自己需要一個共享鎖,那麼就在表上面新增一個意向共享鎖。而如果自己需要的是某行(或者某些行)上面新增一個排他鎖的話,則先在表上面新增一個意向排他鎖。意向共享鎖可以同時並存多個,但是意向排他鎖同時只能有一個存在。

InnoDB另外的兩個表級鎖:

  • 意向共享鎖(IS): 表示事務準備給資料行記入共享鎖,事務在一個資料行加共享鎖前必須先取得該表的IS鎖。

  • 意向排他鎖(IX): 表示事務準備給資料行加入排他鎖,事務在一個資料行加排他鎖前必須先取得該表的IX鎖。

注意:

  1. 這裡的意向鎖是表級鎖,表示的是一種意向,僅僅表示事務正在讀或寫某一行記錄,在真正加行鎖時才會判斷是否衝突。意向鎖是InnoDB自動加的,不需要使用者干預。
  2. IX,IS是表級鎖,不會和行級的X,S鎖發生衝突,只會和表級的X,S發生衝突。

InnoDB的鎖機制相容情況如下:

InnoDB的鎖機制相容情況

當一個事務請求的鎖模式與當前的鎖相容,InnoDB就將請求的鎖授予該事務;反之如果請求不相容,則該事物就等待鎖釋放。

四 死鎖和避免死鎖

InnoDB的行級鎖是基於索引實現的,如果查詢語句為命中任何索引,那麼InnoDB會使用表級鎖. 此外,InnoDB的行級鎖是針對索引加的鎖,不針對資料記錄,因此即使訪問不同行的記錄,如果使用了相同的索引鍵仍然會出現鎖衝突,還需要注意的是,在通過

SELECT ...LOCK IN SHARE MODE;
複製程式碼

SELECT ...FOR UPDATE;
複製程式碼

使用鎖的時候,如果表沒有定義任何索引,那麼InnoDB會建立一個隱藏的聚簇索引並使用這個索引來加記錄鎖。

此外,不同於MyISAM總是一次性獲得所需的全部鎖,InnoDB的鎖是逐步獲得的,當兩個事務都需要獲得對方持有的鎖,導致雙方都在等待,這就產生了死鎖。 發生死鎖後,InnoDB一般都可以檢測到,並使一個事務釋放鎖回退,另一個則可以獲取鎖完成事務,我們可以採取以上方式避免死鎖:

  • 通過表級鎖來減少死鎖產生的概率;
  • 多個程式儘量約定以相同的順序訪問表(這也是解決併發理論中哲學家就餐問題的一種思路);
  • 同一個事務儘可能做到一次鎖定所需要的所有資源。

五 總結與補充

MyISAM和InnoDB儲存引擎使用的鎖:

  • MyISAM採用表級鎖(table-level locking)。
  • InnoDB支援行級鎖(row-level locking)和表級鎖,預設為行級鎖

表級鎖和行級鎖對比:

  • 表級鎖: Mysql中鎖定 粒度最大 的一種鎖,對當前操作的整張表加鎖,實現簡單,資源消耗也比較少,加鎖快,不會出現死鎖。其鎖定粒度最大,觸發鎖衝突的概率最高,併發度最低,MyISAM和 InnoDB引擎都支援表級鎖。
  • 行級鎖: Mysql中鎖定 粒度最小 的一種鎖,只針對當前操作的行進行加鎖。 行級鎖能大大減少資料庫操作的衝突。其加鎖粒度最小,併發度高,但加鎖的開銷也最大,加鎖慢,會出現死鎖。

補充:

頁級鎖: MySQL中鎖定粒度介於行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但衝突多,行級衝突少,但速度慢。頁級進行了折衷,一次鎖定相鄰的一組記錄。BDB支援頁級鎖。開銷和加鎖時間界於表鎖和行鎖之間,會出現死鎖。鎖定粒度界於表鎖和行鎖之間,併發度一般。

參考:

《深入淺出MySQL》

《Java工程師修煉之道》

歡迎關注我的微信公眾號:"Java面試通關手冊"(一個有溫度的微信公眾號,無廣告,單純技術分享,期待與你共同進步~~~堅持原創,分享美文,分享各種Java學習資源。)

最後,就是使用阿里雲伺服器一段時間後,感覺阿里雲真的很不錯,就申請做了阿里雲大使,然後這是我的優惠券地址.

我的公眾號

相關文章