MySQL 透過 Next-Key Locking 技術(行鎖+間隙鎖)避免幻讀問題

lgx211發表於2024-10-16

在MySQL中,InnoDB引擎透過Next-Key Locking技術來解決幻讀問題。幻讀是一種事務併發問題,通常出現在Repeatable Read隔離級別下的範圍查詢操作中。幻讀的現象是,事務在查詢時多次執行相同的範圍查詢,但由於其他事務的插入或刪除操作導致結果不一致,出現“幻覺”一樣的記錄。

Next-Key Locking 技術結合了 行鎖(Record Lock)間隙鎖(Gap Lock),透過鎖定範圍內的記錄和它們之間的間隙,防止其他事務在這些鎖定的區域內插入或刪除資料,從而避免了幻讀問題。

一、什麼是Next-Key Locking?

Next-Key Locking 是一種 鎖定區間 的機制,它由兩部分組成:

  1. 行鎖(Record Lock):鎖定精確的一行資料,防止其他事務對該行資料的修改。
  2. 間隙鎖(Gap Lock):鎖定一行資料之間的“間隙”,防止其他事務在該間隙中插入新資料。

Next-Key Locking 鎖住了當前查詢的行及其“前後”的間隙,這樣不僅可以防止已有記錄的修改,還能防止在查詢範圍內插入新資料,避免了幻讀問題。

二、Next-Key Locking 的原理

Repeatable Read隔離級別下,當執行範圍查詢時,InnoDB會透過Next-Key Locking在範圍內鎖定所有滿足條件的行及其相鄰的間隙。例如,執行下面的SQL語句:

SELECT * FROM users WHERE age BETWEEN 20 AND 30 FOR UPDATE;

這個查詢會鎖定users表中所有滿足age BETWEEN 20 AND 30的行,以及每一行資料之間的“間隙”。具體鎖定機制如下:

  1. 行鎖(Record Lock):鎖定所有符合條件的行,阻止其他事務修改這些行。
  2. 間隙鎖(Gap Lock):鎖定查詢範圍內的行之間的“間隙”,阻止其他事務在這些間隙中插入新行。

假設當前資料如下:

id | age
---------
 1 | 18
 2 | 25
 3 | 28
 4 | 35

執行 SELECT * FROM users WHERE age BETWEEN 20 AND 30 FOR UPDATE; 時,Next-Key Locking 會做如下操作:

  • 鎖住 age=25age=28 這兩行(Record Lock)。
  • 鎖住age > 18age < 35 之間的所有間隙(Gap Lock),即阻止在 age=19age=34 之間插入新行。

這保證了在當前事務提交之前,其他事務無法在查詢的範圍內插入、刪除或修改資料,從而避免了幻讀。

三、Next-Key Locking 的實現機制

  1. Record Lock(行鎖):行鎖是一種精確的鎖,它只會鎖定某個特定的行,防止其他事務修改該行資料。行鎖可以確保事務中的讀寫操作對已經存在的資料行保持一致。
  2. Gap Lock(間隙鎖):間隙鎖是一種範圍鎖,它鎖定資料行之間的間隙。它不會鎖定實際的資料行,而是鎖定行之間的空隙,防止其他事務在這些空隙中插入新的記錄。這種鎖用來解決幻讀問題。
  3. Next-Key Locking(行鎖 + 間隙鎖):Next-Key Locking 結合了行鎖和間隙鎖,它不僅鎖住了精確的資料行,還鎖住了資料行之間的間隙。這樣,Next-Key Locking 能有效防止其他事務在當前查詢的範圍內插入新資料,從而避免幻讀。

四、Next-Key Locking 解決幻讀的過程

Next-Key Locking 是在Repeatable Read隔離級別中使用的,流程大致如下:

  1. 事務A執行一個範圍查詢,例如SELECT * FROM users WHERE age BETWEEN 20 AND 30 FOR UPDATE;。此時,InnoDB 會使用 Next-Key Locking 鎖住範圍內的資料行和間隙,阻止其他事務在該範圍內插入新的記錄。
  2. 事務B嘗試在age=26的位置插入一條新記錄。由於事務A已經透過Next-Key Locking鎖住了age=25age=30之間的間隙,事務B將被阻塞,直到事務A提交或回滾。
  3. 事務A提交或回滾後,事務B才能成功插入資料。如果事務A沒有鎖定這個範圍,事務B插入資料後,事務A再進行範圍查詢時,結果就會不同,導致幻讀的產生。

透過這種方式,Next-Key Locking 解決了由於併發插入導致的幻讀問題。

五、Next-Key Locking 的優勢與限制

優勢

  • 解決幻讀問題:Next-Key Locking 能有效防止在範圍查詢時產生幻讀,保證事務的一致性。
  • 增強資料安全性:鎖住查詢範圍內的間隙,防止其他事務在未提交的情況下對資料進行插入或修改,保證事務中的資料一致性。

限制

  • 降低併發效能:Next-Key Locking 的鎖粒度較大,可能會鎖定大量的行和間隙,導致系統的併發效能下降。
  • 間隙鎖的開銷:間隙鎖會導致無法插入資料到鎖定範圍內的空隙中,這在某些場景下可能影響資料寫入效率,尤其是在高併發寫入的場景。

六、Next-Key Locking 的實際使用場景

  1. 銀行系統中的餘額查詢
    • 在銀行系統中,使用者查詢賬戶餘額時可能會執行範圍查詢(例如,查詢特定時間段的交易記錄)。透過Next-Key Locking,系統可以防止其他事務在這個時間段內插入新的交易記錄,確保使用者每次查詢得到的一致結果。
  2. 電商系統中的訂單查詢
    • 在電商平臺中,使用者查詢某一時間段的訂單時,可能需要保證查詢過程中訂單資料的一致性。透過Next-Key Locking,避免其他使用者在訂單查詢期間插入新的訂單,確保訂單資料的一致性。

七、總結

Next-Key Locking 透過將行鎖和間隙鎖結合起來,解決了MySQL中Repeatable Read隔離級別下的幻讀問題。它不僅鎖住了查詢範圍內的具體資料行,還鎖住了資料行之間的空隙,防止了新資料的插入。雖然這種鎖機制能有效解決併發環境下的資料一致性問題,但也會帶來併發效能的下降,需要在實際業務場景中權衡使用。
看了那麼久別人寫的內容,自己整理,總結歸納一下。言簡意賅

相關文章