首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

InnoDB 死鎖異常處理與重試機制最佳實踐

     編輯:MySQL 綜合教學

場景與異常

執行 UPDATE 時拋出 DeadlockLoserDataAccessException:
Deadlock found when trying to get lock; try restarting transaction

InnoDB 會自動回滾並重試,用戶僅感覺短暫卡頓,但監控系統持續報警,需在應用層處理。

應用層重試模式

/**
 * 死鎖重試封裝
 * @param mapper MyBatis Mapper
 * @param record 實體對象
 */
private void updateWithDeadLock(TestMapper mapper, Test record) throws InterruptedException {
    boolean oops;
    int retries = 5;
    do {
        oops = false;
        try {
            mapper.updateByPrimaryKeySelective(record);
        } catch (DeadlockLoserDataAccessException dlEx) {
            oops = true;
            Thread.sleep((long) (Math.random() * 500)); // 0-500ms 隨機退避
        }
    } while (oops && retries-- > 0);
}

若非 MyBatis,需自行管理連接獲取與關閉。

死鎖原理深度解析

InnoDB 採用行級鎖,分為:

  • 共享鎖 (S):SELECT ... LOCK IN SHARE MODE
  • 排他鎖 (X):UPDATE、DELETE

經典死鎖推演

  1. 事務 A:START TRANSACTION; SELECT * FROM t WHERE i=1 LOCK IN SHARE MODE; → 持有 S 鎖
  2. 事務 B:START TRANSACTION; DELETE FROM t WHERE i=1; → 需 X 鎖,被阻塞,等待 A 釋放 S
  3. 事務 A:DELETE FROM t WHERE i=1; → 需 X 鎖,但 B 已持有 X 鎖並等待 A 的 S 鎖 → 死鎖形成

InnoDB 檢測到死鎖,選擇一個受害者回滾(拋出 1213 錯誤),另一個事務繼續執行。

預防與優化建議

  • 統一加鎖順序:所有事務按相同順序訪問表/行
  • 縮短事務長度:減少鎖持有時間
  • 合理索引:避免全表掃描導致大量行鎖
  • 低隔離級別:READ COMMITTED 可減少間隙鎖
  • 應用層重試:如本文模式,指數退避 + 最大重試次數

死鎖不可完全避免,但通過「規範開發 + 監控告警 + 自動重試」可將業務影響降至最低。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved