文檔版本:8.0
來源:How to Minimize and Handle Deadlocks
上一篇:快照讀與加鎖讀html
本篇介紹如何減小死鎖的發生,以及出現死鎖時如何處理。
死鎖指不一樣的事務因彼此持有對方等待的鎖而不能繼續執行的情形。因雙方都在等待資源釋放,任意一方都不會釋放已有的鎖。mysql
死鎖是事務形數據庫中的經典問題,但只要死鎖的發生不會頻繁到徹底不能執行某個事務,那麼就不算危險。一般,當事務因死鎖而回滾時,你須要讓你的應用隨時作好從新發送事務的準備。算法
InnoDB引擎默認使用行鎖。即便在事務中插入或刪除單行數據,也能觸發死鎖。由於這些操做並非真正的「原子的」,在插入或刪除時它們會給行的索引值(可能有多個)上鎖。sql
在前面的 InnoDB中的鎖 中解釋過:在默認級別
REPEATABLE READ
下,InnoDB在搜索和掃描索引時使用鄰鍵鎖,用於避免幻行。此時InnoDB會無視Where條件的過濾,給每一個掃描到的索引值及其間隙上鎖。此策略適用於加鎖讀、INSERT、DELETE,但有一個特殊場景只會上記錄鎖不會上間隙鎖:WHERE條件中涵蓋了惟一索引。數據庫
經過如下技巧,你能夠處理好死鎖,並減小其發生的機率:併發
隨時使用SHOW ENGINE INNODB STATUS
找出最近發生死鎖的緣由,以便調整應用規避死鎖。函數
若是頻繁的死鎖警告惹人注目,開啓innodb_print_all_deadlocks
選項以收集額外的調試信息。在MySQL的錯誤日誌中會記錄每次死鎖的信息,而不單單記錄最後一次。完成調試後關閉這個選項。設計
隨時準備好重啓因死鎖而失敗的事務。死鎖並不危險,重試就行了。調試
保持事務的短小精悍,以下降衝突的可能性。日誌
作出一系列關聯變動後當即提交事務,以下降衝突的可能性。特別是不要讓有關聯的MySQL會話長時間掛起未提交的事務。
若是使用加鎖讀(SELECT ... FOR UPDATE
或 SELECT ... FOR SHARE
),嘗試使用更低的隔離級別,如READ COMMITTED
。
在同一事務內修改多張表,或一張表內的不一樣行時,每次以相同的順序執行操做。以便讓事務造成清晰的鎖操做隊列而規避死鎖。例如,將數據庫操做編排爲應用內的函數,或調用SQL序列(即MySQL函數或存儲過程),避免將相似的INSERT,UPDATE和DELETE操做分散在代碼各處。
精心設計表索引。讓查詢掃描更少的行數,也就意味着更少的鎖。使用EXPLAIN SELECT
查看MySQL認爲查詢最適合使用的索引。
減小鎖操做。若是能容忍查詢返回老快照中的數據,就不要加FOR UPDATE
或FOR SHARE
子句。READ COMMITTED
級別適合這種場景,由於每次快照讀都會讀取本身的最新快照。
SET autocommit=0; LOCK TABLES t1 WRITE, t2 READ, ...; ... 在表t1和t2上操做 ... COMMIT; UNLOCK TABLES;
表級鎖防止表中的併發更改,經過犧牲響應度避免了死鎖。