死鎖是一種情況,其中多個交易無法繼續,因為每個交易都持有另一個交易需要的鎖定。由於所有相關交易都在等待相同的資源可用,因此它們都不會釋放它所持有的鎖定。
當交易鎖定多個資料表中的列(透過諸如 UPDATE
或 SELECT ... FOR UPDATE
之類的陳述式),但順序相反時,可能會發生死鎖。當此類陳述式鎖定索引記錄和間隙的範圍時,也可能發生死鎖,由於時間問題,每個交易都會取得某些鎖定,但不會取得其他鎖定。有關死鎖範例,請參閱第 17.7.5.1 節「InnoDB 死鎖範例」。
為了減少死鎖的可能性,請使用交易而不是 LOCK TABLES
陳述式;保持插入或更新資料的交易足夠小,使其不會長時間保持開啟狀態;當不同的交易更新多個資料表或大範圍的列時,在每個交易中使用相同的操作順序(例如 SELECT ... FOR UPDATE
);在 SELECT ... FOR UPDATE
和 UPDATE ... WHERE
陳述式中使用的欄位上建立索引。死鎖的可能性不受隔離等級的影響,因為隔離等級會變更讀取操作的行為,而死鎖是因寫入操作而發生。有關避免死鎖狀況和從死鎖狀況中復原的更多資訊,請參閱第 17.7.5.3 節「如何最小化和處理死鎖」。
當啟用死結偵測(預設值)且確實發生死結時,InnoDB
會偵測到此狀況並回滾其中一個交易(犧牲者)。如果使用 innodb_deadlock_detect
變數停用死結偵測,InnoDB
會依賴 innodb_lock_wait_timeout
設定來回滾死結情況下的交易。因此,即使您的應用程式邏輯正確,您仍然必須處理必須重試交易的情況。若要檢視 InnoDB
使用者交易中最後發生的死結,請使用 SHOW ENGINE INNODB STATUS
。如果頻繁的死結突顯交易結構或應用程式錯誤處理的問題,請啟用 innodb_print_all_deadlocks
,將所有死結的相關資訊列印到 mysqld 錯誤日誌中。關於如何自動偵測和處理死結的更多資訊,請參閱 第 17.7.5.2 節,「死結偵測」。