1. 程式人生 > 實用技巧 >簡單理解MySQL鎖

簡單理解MySQL鎖

簡單理解MySQL鎖

前段時間看一些面經,感覺自己MySQL鎖這一塊知識很零碎,決定系統地記錄一下。

閱讀之前預設讀者已瞭解前置知識,也就是事務隔離級別之類的。

什麼是資料庫鎖

鎖是計算機協調多個程序或執行緒併發訪問某一資源的機制。在資料庫中,除傳統的計算機資源(如CPU、RAM、I/O等)的爭用外,資料也是一種供許多使用者共享的資源。如何保證資料併發訪問的一致性、有效性是所有資料庫必須解決的一個問題,鎖衝突也是影響資料併發訪問效能的一個重要因素。從這個角度來說,鎖對資料庫而言顯得尤其重要,也更加複雜。

鎖的分類

資料庫鎖 (可以理解為資料庫的行鎖與表鎖)

  • 資料庫鎖適用於叢集
  • 粒度小,更方便控制

程式碼鎖(可以理解為 共享鎖 / 讀鎖 與 排他鎖 / 寫鎖)

  • 需要複雜的處理,才能作用於叢集
  • 粒度大

行鎖 & 表鎖

說明:只有「明確」指定主鍵,才會執行鎖,否則將會執行表鎖

示例

假設有個表 products ,欄位id、name、type,id是主鍵。

  • 無鎖

    # 明確指定主鍵,但不存在該主鍵的值(沒有資料,當然不會有鎖)
    SELECT * FROM products WHERE id=-1 FOR UPDATE;
    
  • 行鎖

    # 明確指定主鍵
    SELECT * FROM products WHERE id=3 FOR UPDATE;
    SELECT * FROM products WHERE id=3 AND type=1 FOR UPDATE;
    
  • 表鎖

    # 主鍵不明確
    SELECT * FROM products WHERE name='Mouse' FOR UPDATE;
    SELECT * FROM products WHERE id<>'3' FOR UPDATE;
    SELECT * FROM products WHERE id LIKE '3' FOR UPDATE;
    

注意

  • 要測試鎖定的狀況,可以利用 MySQL 的 Command Mode ,開二個視窗來做測試。
  • MyAsim 只支援表級鎖,InnerDB支援行級鎖添加了(行級鎖、表級鎖)鎖的資料不能被其它事務再鎖定,也不被其它事務修改(修改、刪除) 。是表級鎖時,不管是否查詢到記錄,都會鎖定表。

行鎖演算法

Record Lock(普通行鎖)

  • 對於鍵值在條件範圍內,且存在的記錄,使用" Record Lock ",即普通的行鎖機制;

Gap Lock(間隙鎖)

比如一張表沒有id為10~20 的欄位,我鎖了130之間的所有值,那麼插入值如果在1020之間的話,也會被阻塞,在某些情況下會極大地浪費效能。

  • 對於鍵值在條件範圍內但並不存在的記錄,叫做" 間隙(GAP) ",InnoDB會對這個“間隙”加鎖,這種鎖機制就是所謂的" Gap Lock "(間隙鎖);

Next-Key Lock(行 & 間隙)

  • 對於存在於不存在的資料同時加鎖,則稱為" Next-Key Lock ";

  • Next-Key Lock包含Record Lock和Gap Lock;

    # 假如user表中只有101條記錄,empid的值是1,2,...,100,101
    # 範圍條件的檢索,會對值為101的記錄加鎖,也會對大於101(不存在)加鎖
    # 由於兩個鎖同時存在,則此處為 Next-Key Lock
    select * from  user where user_id > 100 for update;
    

表鎖演算法

意向鎖

  • 當一個事務帶著表鎖去訪問一個被加了行鎖的資源,那麼,此時,這個行鎖就會升級為意向鎖,將表鎖住。
  • 常用的意向鎖有:意向共享鎖,意向排它鎖,共享意向排它鎖

自增鎖

  • 事務插入自增型別的列時獲取自增鎖

    如果一個事務正在往表中插入自增記錄,所有其他事務的插入必須等待

實現

共享鎖 & 排它鎖

行鎖和表鎖是鎖粒度的概念,共享鎖和排它鎖是他們的具體實現

共享鎖(S):讀鎖

  • 允許一個事務去讀一行,阻止其他事務獲取該行的排它鎖。
  • 多事務時,只能加共享讀鎖,不能加排他寫鎖;單事務時,可以加任何鎖。
  • 一般理解為:能讀,不能寫。

排它鎖(X):寫鎖

  • 允許持有排它鎖的事務讀寫資料,阻止其他事物獲取該資料的共享鎖和排它鎖。
  • 其他事務不能獲取該資料的任何鎖,直到排它鎖持有者釋放。
  • 不能獲取任何鎖,不代表不能無鎖讀取。

注意

  • 排它鎖指的是,在某個事務獲取資料的排它鎖後,其他事務不能獲取該資料的任何鎖, 並不代表其他事務不能無鎖讀取該資料。
    • 無鎖
      • select ... from
    • 共享鎖
      • select ... lock in share mode
    • 排它鎖
      • update
      • delete
      • insert
      • select ... for update
  • MySQL8.0 中,使用 FOR SHARE 替代了 LOCK IN SHARE MODE,但仍然支援 LOCK IN SHARE MODE; 雖然是等價的,但是 FOR SHARE 支援 NOWAIT 、 SKIP LOCKED 等,配合自旋,可以實現高效的等待佇列。

樂觀鎖 & 悲觀鎖

不管是什麼鎖都需要增加,需加失敗重試

樂觀鎖

  • 通過版本號來進行更新的操作屬於樂觀鎖

    update tab set name = 'xxx' where id = 1 and version = xxx
    

悲觀鎖

共享鎖 & 排它鎖都是悲觀鎖的具象實現

  • 顯示地控制行或表鎖屬於悲觀鎖