生產環境拋出 Deadlock found when trying to get lock; try restarting transaction,通過 SHOW ENGINE INNODB STATUS 定位到具體 SQL,根因是 **WHERE 條件列缺少索引,導致行鎖退化為表鎖**,並發下極易死鎖。
org.springframework.dao.DeadlockLoserDataAccessException: ... Caused by: com.mysql.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
框架層面:iBATIS + Spring + c3p0 連接池。
MySQL 命令行執行:
SHOW ENGINE INNODB STATUS\G
輸出 LATEST DETECTED DEADLOCK 區塊,可見死鎖涉及語句:
UPDATE `table_name` SET xx=xxx WHERE xxx=xxx; -- WHERE 列 xxx 無索引
ALTER TABLE `table_name` ADD INDEX `idx_xxx` (`xxx`); -- 為 WHERE 列添加索引
加索引後,更新可精準定位行記錄,僅加行鎖,死鎖概率大幅降低 (僅在真正行衝突時發生)。
UPDATE/DELETE/SELECT ... FOR UPDATE 的 WHERE 條件列**必須有索引覆蓋**。pt-deadlock-logger 或監控 Innodb_deadlocks 狀態變量。Rows_examined 遠大於 Rows_sent 的更新語句。| 現象 | 錯誤碼 | 原因 | 對策 |
|---|---|---|---|
| Deadlock | 1213 (ER_LOCK_DEADLOCK) | 循環等待,檢測器主動回滾受害者 | 優化索引/訪問順序/縮短事務 |
| Lock Wait Timeout | 1205 (ER_LOCK_WAIT_TIMEOUT) | 等待鎖超過 innodb_lock_wait_timeout (默認 50s) | 排查長事務/大批量更新/熱點行 |