簡介 什麼是死鎖? 我認為,死鎖是由於兩個對象在擁有一份資源的情況下申請另一份資源,而另一份資源恰好又是這兩對象正持有的,導致兩對象無法完成操作,且所持資源無法釋放。 什麼又是阻塞? 阻塞是由於資源不足引起的排隊等待現象。比如同時兩個進程去更新一個表。 這裡我們可以把阻塞作為死鎖的必要條件。下麵我們
簡介
什麼是死鎖?
我認為,死鎖是由於兩個對象在擁有一份資源的情況下申請另一份資源,而另一份資源恰好又是這兩對象正持有的,導致兩對象無法完成操作,且所持資源無法釋放。
什麼又是阻塞?
阻塞是由於資源不足引起的排隊等待現象。比如同時兩個進程去更新一個表。
這裡我們可以把阻塞作為死鎖的必要條件。下麵我們先理解一下死鎖和阻塞再來看一下我最近遇到一個問題以及解決思路。
SQLServer中的死鎖
對應到SQL Server中,當在兩個或多個任務中,如果每個任務鎖定了其他任務試圖鎖定的資源,此時會造成這些任務永久阻塞,從而出現死鎖;
這些資源可能是:單行(RID,堆中的單行)、索引中的鍵(KEY,行鎖)、頁(PAG,8KB)、區結構(EXT,連續的8頁)、堆或B樹(HOBT) 、表(TAB,包括數據和索引)、文件(File,資料庫文件)、應用程式專用資源(APP)、元數據(METADATA)、分配單元(Allocation_Unit)、整個資料庫(DB)。
下麵我簡單舉一個例子來說明一下死鎖的原理:
如圖,按步驟執行:
1. begin tran
update test1 set aaa=1
2.
begin tran
update test2 set aaa=1
update test1 set bbb=2
3.再次執行圖1中的Update test2 set bbb=2
執行完成後發現數據並未插入,且一直處於running狀態
這個時候我們通過語句查詢死鎖的進程和語句。得到如下結果:
很容易發現發生死鎖的語句,也可以使用 SQL Server Profiler 分析死鎖: 將 Deadlock graph 事件類添加到跟蹤。此事件類使用死鎖涉及到的進程和對象的 XML 數據填充跟蹤中的 TextData 數據列。SQL Server 事件探查器 可以將 XML 文檔提取到死鎖 XML 文件中,以後可在 SQL Server Management Studio 中查看該文件。如圖:
接下來我們說一下如何處理死鎖
1.臨時解決方案,先Kill 掉死鎖的進程,只是暫時解決這個問題。
2.SQL Server自動選擇一條SQL作死鎖犧牲品:當死鎖發生時,鎖監視器線程執行死鎖檢查,資料庫引擎 選擇運行回滾開銷最小的事務的會話作為死鎖犧牲品,返回1205 錯誤,回滾死鎖犧牲品的事務並釋放該事務持有的所有鎖,使其他線程的事務可以請求資源並繼續運行。
伺服器: 消息 1205,級別 13,狀態 50,行 1 事務(進程 ID xx)與另一個進程已被死鎖在 lock 資源上,且該事務已被選作死鎖犧牲品。請重新運行該事務。3.使用SET LOCK_TIMEOUT timeout_period(單位為毫秒)來設定請求超時。
4.在SQLServer 和程式兩個方面都可以做代碼上修正,這裡不在詳細描述,主要是通過發現死鎖等待一段時間後再次嘗試的方式來解決。
預防和避免死鎖
1.儘量減少事務執行的時間。
2.在合理的範圍內降低隔離級別。
3.同一個事務內儘量避免出現迴圈對同一個表的處理。
4.同一個事務內較少用戶交互,即鎖的競爭。
5.儘量保證邏輯處理的順序比如對錶的處理都按照一個順序進行。
6.對於需要各種邏輯處理的表,可以通過增加索引的方式來減少鎖的競爭。
7.儘量減少非聚集索引的include 的列,也能減少外鍵死鎖的發生。
8.同一個對象儘量採用select 在update 前來使用。
9.對於實時性要求不高的可以使用with(nolock)來實現對錶的查詢,但是可能會差生臟讀。
總結
本文簡單的介紹了死鎖的原因,如何解決和預防。當然任何事情都是雙刃劍,還要我們根據實際情況來合理減少死鎖和阻塞的發生;對於不同隔離界別鎖帶來的問題可以看一下我之前的一篇關於鎖的介紹。希望對死鎖發生預防和解決有一定的幫助。