簡單理解MySQL鎖
阿新 • • 發佈:2020-07-20
簡單理解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
悲觀鎖
共享鎖 & 排它鎖都是悲觀鎖的具象實現
- 顯示地控制行或表鎖屬於悲觀鎖