首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 解決搶購/秒殺/抽獎高併發導致庫存扣減為負數的方案(文件排他鎖 flock)

     編輯:PHP 相關知識

問題本質

「查庫存 → 判斷 >0 → 扣減」非原子操作。高併發下多進程同時讀到庫存 >0,均執行扣減,導致庫存變負(超賣)。

常見方案對比

flock 方案代碼實現

阻塞模式(等待鎖釋放)

非阻塞模式(立即返回,忙則拒絕)

關鍵注意點

  • lock.txt 需預先建立並可寫,建議放在項目 Runtime/Lock/ 目錄。
  • 鎖粒度:全局單文件鎖簡單但並發上限低(~幾百 QPS)。高併發建議按商品 ID 分文件鎖 lock_{$goods_id}.txt。
  • 務必 fclose 釋放文件句柄,否則鎖長期持有導致死結。
  • 分佈式/多機部署需升級為 Redis 分佈式鎖 (SET NX EX) 或數據庫行鎖,flock 僅適用單機。

進階:結合 SQL 條件更新雙重保障

if (flock($fp, LOCK_EX | LOCK_NB)) {
    $affected = $db->execute("UPDATE goods SET stock=stock-1 WHERE id={$id} AND stock>0");
    if ($affected) { /* 成功 */ }
    else { /* 庫存不足 */ }
    flock($fp, LOCK_UN);
}

應用層鎖 + 數據庫層條件更新,雙重保險,極大降低超賣風險。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案原理優點缺點
單進程隊列請求入隊,消費者串行處理徹底串行化需額外進程、有延遲、架構複雜
樂觀鎖查庫存+版本號,更新時比對版本無鎖、高併發友好重試邏輯複雜、寫衝突多時性能差
SQL 條件更新UPDATE ... SET stock=stock-1 WHERE id=1 AND stock>0原子級、極簡需依賴資料庫行鎖、死鎖風險
文件排他鎖 flock進程級串行化關鍵區輕量、無額外組件、跨資料庫單機限制、性能上限受文件系統影響