電商庫存管理的處理架構 - 悲觀鎖


Posted by altheachu on 2025-07-23

悲觀鎖是 Pessimistic Lock的直譯,它的意思可以從2個方面來記憶:

  • Pessimistic:根據劍橋字典,悲觀即「認為壞事比較可能發生」。所謂的「壞事」是指資料的衝突與不一致,特別是在多人或多個程序同時操作同個資源時。

Pessimistic: thinking that bad things are more likely to happen or emphasizing the bad part of a situation:

  • Lock:為了避免資料衝突,某一使用者或程序A可以在讀取或寫入資源前,先將資源上鎖。

而「悲觀鎖」的意思,是讓這個鎖具有排他性,也就是在A完成操作並釋放鎖前,其他使用者或程序無法修改被鎖定的資源。

特性

悲觀鎖是透過事務(Transaction)機制實作,並衍生出對應的特性。所以在了解悲觀鎖之前,我們先複習一下事務是什麼。

事務

進行一個業務功能時,可能涉及多資料表的操作,例如訂單成立時,庫存應同步減少對應的數量。為了達到這個效果,可以使用事務來確保兩者同步。

事務是資料庫操作的邏輯單位,如果同一個事務內的操作不是全部成功,就會全部失敗。如果操作中已修改A表跟B表,但操作C表未成功,資料庫也會將A表跟B表恢復到未修改前的狀態,這個特性稱為「回滾(rollback)」。

悲觀鎖即是確保資料在同一時間只能被一個事務內的操作修改。

優點

  1. 保證資料的一致性:因為同一時間不會有兩個事務同時修改一筆資料。
  2. 可搭配公平鎖、Queue等機制控制執行順序:有些資料庫預設是FIFO,即先請求的先處理,但並非絕對,所以可進一步搭配公平鎖與Queue 確保FIFO。

缺點

  1. 可能造成不良的使用體驗:在事務的機制下,除了讀取外,一個事務內的操作必定要等當前獲得鎖的事務結束後才能進行,所以可能會增加等待時間,並造成系統吞吐量下降。

適用情境

事務高衝突時:如銀行的大量交易,用悲觀鎖可以避免資源同時被多個事務修改,維持資料的一致性;又例如電商搶購活動競爭少量庫存,悲觀鎖可以避免超賣,若DB本身採用FIFO,也確保了公平性。

其他補充

  1. 行鎖、表鎖、讀鎖、寫鎖等用 Synchronized 實現的鎖皆為悲觀鎖。行鎖在電商庫存管理的應用可以詳閱電商庫存管理的處理架構 - 行鎖
  2. 悲觀鎖的鎖頭欄位需務必加上索引,因為在沒有索引的時候,sql的查詢會一行行掃描,直到找到對應的鎖頭值,而被掃描過的資料行都會在過程中被加上悲觀鎖。

資料庫實作

這篇是用MySQL的Workbench來演示扣庫過程悲觀鎖的應用。假設現在有一張資料表book,欄位stock記錄著書籍的庫存。

Table Book

按照以下步驟模擬多個事務同時扣庫的情形,而在這個工具中,多個事務需透過多個DB Session開啟:

  • 開啟一個Session,使用begin字符開啟事務,避免MySQL自動提交。這個Session下文稱為Session A。

begin;

  • 假設要購買ID為1的書,先將此行資料上悲觀鎖。

SELECT * FROM bookstore.book where book_id = 1 for update;

  • 開啟另一個Session,重複步驟1跟2,開啟事務並上悲觀鎖。
begin;
SELECT * FROM bookstore.book where book_id = 1 for update;

此時會發現無法順利查詢,訊息顯示Running。這是由於Session A已經把這行資料鎖住了。

查詢後訊息顯示為Running

  • 在Session A 的 console執行扣庫,並在查詢結果符合預期,提交事務。
update bookstore.book set stock = stock - 1 where book_id = 1 and stock > 0;
SELECT * FROM bookstore.book where book_id = 1;
commit;
  • 切回Session B,可以發現查詢訊息由Running改為1 row(s) returned,且結果也順利回傳了,代表此時由Session B取得悲觀鎖。

Session B查詢結果順利返回

參考資料

  1. Optimistic Locking vs Pessimistic Locking: Managing Concurrent Access
  2. SQL 樂觀鎖悲觀鎖
  3. 關聯式資料庫與交易(Transaction)機制入門
  4. 關聯式資料庫要如何設計避免超賣?

#悲觀鎖 #電商超賣







Related Posts

EsLint 我們重頭來過吧

EsLint 我們重頭來過吧

來寫測試吧!

來寫測試吧!

Debounce 與 Memoize

Debounce 與 Memoize


Comments