數據庫中常見的死鎖原因與解決方案


死鎖在操作系統中指的是兩個或兩個以上的進程在執行的過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或者系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。
在操作系統中,死鎖的處理是一個重要的話題,也已經有較為成熟的解決方法,如銀行家算法等,在這邊我們就不再闡述,只討論數據庫中的死鎖。

1. 事務之間對資源訪問順序的交替
出現原因:
一個用戶A 訪問表A(鎖住了表A),然后又訪問表B;另一個用戶B 訪問表B(鎖住了表B),然后企圖訪問表A;這時用戶A由於用戶B已經鎖住表B,它必須等待用戶B釋放表B才能繼續,同樣用戶B要等用戶A釋放表A才能繼續,這就死鎖就產生了。

解決方法:
這種死鎖比較常見,是由於程序的BUG產生的,除了調整的程序的邏輯沒有其它的辦法。仔細分析程序的邏輯,對於數據庫的多表操作時,盡量按照相同的順序進行處理,盡量避免同時鎖定兩個資源,如操作A和B兩張表時,總是按先A后B的順序處理, 必須同時鎖定兩個資源時,要保證在任何時刻都應該按照相同的順序來鎖定資源

2. 並發修改同一記錄
出現原因:主要是由於沒有一次性申請夠權限的鎖導致的。參考:記錄一次死鎖排查過程

用戶A查詢一條紀錄,然后修改該條紀錄;這時用戶B修改該條紀錄,這時用戶A的事務里鎖的性質由查詢的共享鎖企圖上升到獨占鎖,而用戶B里的獨占鎖由於A有共享鎖存在所以必須等A釋放掉共享鎖,而A由於B的獨占鎖而無法上升的獨占鎖也就不可能釋放共享鎖,於是出現了死鎖。這種死鎖比較隱蔽,但在稍大點的項目中經常發生。

解決方法:

a. 樂觀鎖,實現寫-寫並發

b. 悲觀鎖:使用悲觀鎖進行控制。悲觀鎖大多數情況下依靠數據庫的鎖機制實現,如Oracle的Select … for update語句,以保證操作最大程度的獨占性。但隨之而來的就是數據庫性能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受。

3. 索引不當導致的死鎖
出現原因:
如果在事務中執行了一條不滿足條件的語句,執行全表掃描,把行級鎖上升為表級鎖,多個這樣的事務執行后,就很容易產生死鎖和阻塞。類似的情況還有當表中的數據量非常龐大而索引建的過少或不合適的時候,使得經常發生全表掃描,最終應用系統會越來越慢,最終發生阻塞或死鎖。

另外一種情況是由於二級索引的存在,上鎖的順序不同導致的,這部分在討論索引時會提到。參考:https://www.cnblogs.com/LBSer/p/5183300.html

解決方法:

SQL語句中不要使用太復雜的關聯多表的查詢;使用“執行計划”對SQL語句進行分析,對於有全表掃描的SQL語句,建立相應的索引進行優化。

那么,如何盡可能的避免死鎖呢?
1)以固定的順序訪問表和行。即按順序申請鎖,這樣就不會造成互相等待的場面。
2)大事務拆小。大事務更傾向於死鎖,如果業務允許,將大事務拆小。
3)在同一個事務中,盡可能做到一次鎖定所需要的所有資源,減少死鎖概率。
4)降低隔離級別。如果業務允許,將隔離級別調低也是較好的選擇,比如將隔離級別從RR調整為RC,可以避免掉很多因為gap鎖造成的死鎖。
5)為表添加合理的索引。如果不走索引將會為表的每一行記錄添加上鎖,死鎖的概率大大增大。



作者:蓉蓉65163
鏈接:https://www.jianshu.com/p/7401cb087651
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

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



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