MySQL死鎖


死鎖產生

死鎖是指兩個或多個事務在同一資源上相互占用,並請求鎖定對方占用的資源,從而導致惡性循環。

當事務試圖以不同的順序鎖定資源時,就可能產生死鎖。多個事務同時鎖定同一個資源時也可能會產生死鎖。

鎖的行為和順序和存儲引擎相關。以同樣的順序執行語句,有些存儲引擎會產生死鎖有些不會——死鎖有雙重原因:真正的數據沖突;存儲引擎的實現方式。

檢測死鎖

數據庫系統實現了各種死鎖檢測和死鎖超時的機制。InnoDB存儲引擎能檢測到死鎖的循環依賴並立即返回一個錯誤。

死鎖恢復

死鎖發生以后,只有部分或完全回滾其中一個事務,才能打破死鎖,InnoDB目前處理死鎖的方法是,將持有最少行級排他鎖的事務進行回滾。所以事務型應用程序在設計時必須考慮如何處理死鎖,多數情況下只需要重新執行因死鎖回滾的事務即可。

外部鎖的死鎖檢測

發生死鎖后,InnoDB 一般都能自動檢測到,並使一個事務釋放鎖並回退,另一個事務獲得鎖,繼續完成事務。但在涉及外部鎖,或涉及表鎖的情況下,InnoDB 並不能完全自動檢測到死鎖, 這需要通過設置鎖等待超時參數 innodb_lock_wait_timeout 來解決

死鎖影響性能

死鎖會影響性能而不是會產生嚴重錯誤,因為InnoDB會自動檢測死鎖狀況並回滾其中一個受影響的事務。在高並發系統上,當許多線程等待同一個鎖時,死鎖檢測可能導致速度變慢。 有時當發生死鎖時,禁用死鎖檢測(使用innodb_deadlock_detect配置選項)可能會更有效,這時可以依賴innodb_lock_wait_timeout設置進行事務回滾。

MyISAM避免死鎖

在自動加鎖的情況下,MyISAM 總是一次獲得 SQL 語句所需要的全部鎖,所以 MyISAM 表不會出現死鎖。

InnoDB避免死鎖

  • 為了在單個InnoDB表上執行多個並發寫入操作時避免死鎖,可以在事務開始時通過為預期要修改的每個元祖(行)使用SELECT ... FOR UPDATE語句來獲取必要的鎖,即使這些行的更改語句是在之后才執行的。
  • 在事務中,如果要更新記錄,應該直接申請足夠級別的鎖,即排他鎖,而不應先申請共享鎖、更新時再申請排他鎖,因為這時候當用戶再申請排他鎖時,其他事務可能又已經獲得了相同記錄的共享鎖,從而造成鎖沖突,甚至死鎖
  • 如果事務需要修改或鎖定多個表,則應在每個事務中以相同的順序使用加鎖語句。在應用中,如果不同的程序會並發存取多個表,應盡量約定以相同的順序來訪問表,這樣可以大大降低產生死鎖的機會
  • 通過SELECT ... LOCK IN SHARE MODE獲取行的讀鎖后,如果當前事務再需要對該記錄進行更新操作,則很有可能造成死鎖。
  • 改變事務隔離級別

如果出現死鎖,可以用 SHOW INNODB STATUS 命令來確定最后一個死鎖產生的原因。返回結果中包括死鎖相關事務的詳細信息,如引發死鎖的 SQL 語句,事務已經獲得的鎖,正在等待什么鎖,以及被回滾的事務等。據此可以分析死鎖產生的原因和改進措施。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM