執行 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 採用行級鎖,分為:
SELECT ... LOCK IN SHARE MODEUPDATE、DELETESTART TRANSACTION; SELECT * FROM t WHERE i=1 LOCK IN SHARE MODE; → 持有 S 鎖START TRANSACTION; DELETE FROM t WHERE i=1; → 需 X 鎖,被阻塞,等待 A 釋放 SDELETE FROM t WHERE i=1; → 需 X 鎖,但 B 已持有 X 鎖並等待 A 的 S 鎖 → 死鎖形成InnoDB 檢測到死鎖,選擇一個受害者回滾(拋出 1213 錯誤),另一個事務繼續執行。
READ COMMITTED 可減少間隙鎖死鎖不可完全避免,但通過「規範開發 + 監控告警 + 自動重試」可將業務影響降至最低。