介紹下InnoDB的鎖機制?你學會了嗎?
在InnoDB中,鎖可以分為兩種級別,一種是共享鎖(S鎖),另一種是排他鎖(X鎖)。
共享鎖&排他鎖
共享鎖又稱為讀鎖,由讀取操作創建。其他用戶可以并發讀取數據,但直到所有共享鎖都被釋放之前,任何事務都無法對數據進行修改(獲得數據上的排他鎖)。
如果事務T對數據A加上共享鎖后,其他事務只能對A再加共享鎖,而不能加排他鎖。獲得共享鎖的事務只能讀取數據,而不能修改數據。
SELECT ... LOCK IN SHARE MODE;
在查詢語句后添加LOCK IN SHARE MODE,MySQL會為查詢結果中的每行加上共享鎖。只有當沒有其他線程對查詢結果集中的任意行使用排他鎖時,才能成功獲取共享鎖;否則將被阻塞。其他線程可以讀取已經被加了共享鎖的表,且這些線程將讀取相同版本的數據。
排他鎖又稱為寫鎖,一旦事務T對數據A加上排他鎖,其他事務就無法再對A加任何類型的鎖。獲得排他鎖的事務既可讀取數據,又可修改數據。
SELECT ... FOR UPDATE;
除了S鎖和X鎖之外,InnoDB還有另外兩種鎖,分別是IX鎖和IS鎖,這里的"I"代表著"Intention",即意向鎖。IX即意向排他鎖,IS即意向共享鎖。
在查詢語句后添加FOR UPDATE,MySQL會對查詢命中的每條記錄都加排他鎖(如果有索引,則通過索引加鎖;如果沒有索引,則會鎖定整個表)。只有當沒有其他線程對查詢結果集中的任何一行使用排他鎖時,才能成功申請排他鎖;否則將被阻塞。
意向鎖
在MySQL的InnoDB引擎中,支持多種鎖級別,包括行級鎖和表級鎖。當多個事務需要訪問共享資源時,如果每個事務都直接請求鎖,可能會導致彼此相互阻塞,甚至引發死鎖。
舉個例子:
事務A對表Table1中的某一行加上了行級鎖,這導致該行只能讀取而不能修改。與此同時,事務B試圖申請對Table1的表級鎖。如果事務B成功獲取表級鎖,那么它就能修改表中的任意一行記錄,從而引發沖突。
為解決這一問題,事務B在申請Table1的表級鎖時,需要先檢查是否有其他事務已經加了行級鎖。然而,事務B無法簡單地遍歷表中所有數據逐行判斷是否已被鎖定,這樣效率太低了。
為了解決這一問題,MySQL引入了意向鎖機制。意向鎖作為一種鎖機制,在數據庫管理系統中旨在協調不同鎖粒度(如行級鎖和表級鎖)之間的并發問題。(對于同一鎖粒度內的并發問題,如多個行級鎖之間的沖突,則通過行級互斥鎖來解決。)
注意:
- 意向鎖并非直接鎖定資源,而是用于通知其他事務,以防止它們在相同資源上設置不兼容的鎖。
- 意向鎖不是由用戶直接請求的,而是由MySQL系統管理的。
當一個事務請求獲取行級鎖或表級鎖時,MySQL會自動獲取相應表的意向鎖。這樣一來,其他事務在請求表鎖時,可以先通過該意向鎖探知是否有已經加鎖,并根據意向鎖的類型(意向共享鎖/意向排它鎖)判斷自身是否可獲取鎖。這種方式在不阻塞其他事務的情況下,為當前事務鎖定資源。
意向鎖有兩種類型:意向共享鎖和意向排它鎖。
- 意向共享鎖:代表事務打算對資源設置共享鎖(讀鎖)。通常用于暗示事務打算讀取資源,不希望在讀取時有其他事務設置排它鎖。
- 意向排它鎖:代表事務打算對資源設置排它鎖(寫鎖)。這表明事務計劃修改資源,不希望其他事務同時設置共享或排它鎖。
意向鎖是表級鎖,在觸發意向鎖的事務提交或回滾后會釋放。
以下是MySQL官網上給出的這幾種鎖之間的沖突關系:
★
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html
圖片
記錄鎖
記錄鎖(Record Lock)是一種加在索引記錄上的鎖,用于保護特定行數據的完整性。例如,對于語句 SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;,將會對滿足條件 c1=10 的記錄加鎖,以防止其他事務對該行進行插入、更新或刪除操作。
盡管記錄鎖通常被稱為行級鎖,但需要特別注意的是,它實際上鎖定的是索引記錄而非數據行本身。此外,記錄鎖僅限于鎖定索引。
當表中不存在索引時該如何處理?InnoDB 引擎會自動創建一個隱藏的聚簇索引,并使用該索引進行記錄鎖定。
★
若表中未定義主鍵,MySQL會默認選擇一個唯一的非空索引作為聚簇索引。若不存在適用的非空唯一索引,則會創建一個隱藏的主鍵(row_id)作為聚簇索引。
關于記錄鎖的加鎖原則。感興趣的小伙伴一鍵三連。后續可以出一片文章。
插入記錄鎖
插入意向鎖是一種由插入操作在行插入之前設置的間隙鎖。這種鎖表明了插入的意圖,以這樣一種方式,如果多個事務嘗試插入到同一索引間隙但不在間隙內的相同位置,則它們不需要相互等待。
舉例來說,假設存在索引記錄的值為4和7。當不同事務分別嘗試插入值為5和6時,它們會在獲取插入行的獨占鎖之前,各自使用插入意向鎖鎖定4和7之間的間隙。由于它們插入的行并不沖突,因此它們不會相互阻塞。然而,如果它們都試圖插入6,那么就會發生阻塞情況。
AUTO-INC 鎖
AUTO-INC 鎖是一種特殊的表級鎖,由向包含 AUTO_INCREMENT 列的表插入數據的事務所獲取。在最簡單的情況下,如果一個事務正在向表中插入值,其他任何事務都必須等待,以便執行它們自己的插入操作,這樣第一個事務插入的行就會接收到連續的主鍵值。
innodb_autoinc_lock_mode 變量控制用于自增鎖定的算法。它允許你在可預測的自增值序列和插入操作的最大并發性之間進行權衡。