死鎖發生的根本根源:資源競爭與相反的加鎖順序
當兩個或多個獨立交易同時進行,且各自持有一部分資源的排他鎖(X Lock),同時又嘗試獲取對方已持有的鎖時,資料庫引擎便會偵測到循環等待圖譜(Wait-For Graph),從而被迫回滾其中一個交易(Deadlock Victim)。在高頻工單流轉、庫存扣減或帳務結算場景中,死鎖往往不是偶發故障,而是架構設計缺乏全域加鎖契約的必然結果。
最常見的三大死鎖誘因
在我們的諮詢輔導經驗中,高達 80% 的死鎖源於以下三種反模式: 1. 業務邏輯中多行更新順序不一致:交易 A 先更新帳戶 ID 1 再更新 ID 2,而交易 B 同時先更新 ID 2 再更新 ID 1。解法是在代碼層面嚴格對涉及的主鍵集合進行排序(如 `ORDER BY id ASC`)後再循序加鎖。 2. 外鍵欄位遺漏索引引發的級聯鎖定:在 PostgreSQL 或 MySQL 中,若子表的外鍵欄位沒有建立獨立索引,當父表進行更新或刪除時,資料庫可能被迫對子表進行全表掃描或升級鎖定層級,引發意想不到的鎖定衝突。 3. Gap Lock 與 Next-Key Lock 的隱形碰撞:在可重複讀(Repeatable Read)隔離等級下,範圍查詢與插入意向鎖之間的重疊常會在高頻寫入時觸發連鎖死鎖。
從架構層面防禦死鎖:樂觀鎖與異步隊列化
消滅死鎖的最有效途徑不是調高資料庫硬體規格,而是從交易邊界入手。將原本大而全的長交易拆分為極短的小交易;針對熱點資源引入版本號(Version Column)之樂觀鎖機制;在面臨極端熱點搶購時,將寫入操作前置到記憶體訊息隊列進行串行化處理,徹底消除資料庫底層的鎖定競爭。