發生死鎖的情況以及解決的辦法

死鎖是指在一組進程中的各個進程均佔有不會釋放的資源,但因互相申請被其他進程所站用不會釋放的資源而處於的一種永久等待狀態。

    死鎖的四個必要條件

互斥條件(Mutual exclusion):資源不能被共享,只能由一個進程使用。
請求與保持條件(Hold and wait):已經得到資源的進程可以再次申請新的資源。
非剝奪條件(No pre-emption):已經分配的資源不能從相應的進程中被強制地剝奪。
循環等待條件(Circular wait):系統中若干進程組成環路,該環路中每個進程都在等待相鄰進程正佔用的資源。

避免死鎖

    上面1中列出了死鎖的四個必要條件,我們只要想辦法破其中的任意一個或多個條件,就可以避免死鎖發生,一般有以下幾種方法(FROM Sql Server 2005聯機叢書):
(1).按同一順序訪問對象。(注:避免出現循環)
(2).避免事務中的用戶交互。(注:減少持有資源的時間,較少鎖競爭)
(3).保持事務簡短並處於一個批處理中。(注:同(2),減少持有資源的時間)
(4).使用較低的隔離級別。(注:使用較低的隔離級別(例如已提交讀)比使用較高的隔離級別(例如可序列化)持有共享鎖的時間更短,減少鎖競爭)
(5).使用基於行版本控制的隔離級別:2005中支持快照事務隔離和指定READ_COMMITTED隔離級別的事務使用行版本控制,可以將讀與寫操作之間發生的死鎖機率降至最低:
SET ALLOW_SNAPSHOT_ISOLATION ON --事務可以指定 SNAPSHOT 事務隔離級別;
SET READ_COMMITTED_SNAPSHOT ON  --指定 READ_COMMITTED 隔離級別的事務將使用行版本控制而不是鎖定。默認情況下(沒有開啓此選項,沒有加with nolock提示),SELECT語句會對請求的資源加S鎖(共享鎖);而開啓了此選項後,SELECT不會對請求的資源加S鎖。
注意:設置 READ_COMMITTED_SNAPSHOT 選項時,數據庫中只允許存在執行 ALTER DATABASE 命令的連接。在 ALTER DATABASE 完成之前,數據庫中決不能有其他打開的連接。數據庫不必一定要處於單用戶模式中。
(6).使用綁定連接。(注:綁定會話有利於在同一臺服務器上的多個會話之間協調操作。綁定會話允許一個或多個會話共享相同的事務和鎖(但每個回話保留其自己的事務隔離級別),並可以使用同一數據,而不會有鎖衝突。可以從同一個應用程序內的多個會話中創建綁定會話,也可以從包含不同會話的多個應用程序中創建綁定會話。在一個會話中開啓事務(begin tran)後,調用exec sp_getbindtoken @Token out;來取得Token,然後傳入另一個會話並執行EXEC sp_bindsession @Token來進行綁定(最後的示例中演示了綁定連接)。

死鎖處理方法:

(1). 根據2中提供的sql,查看那個spid處於wait狀態,然後用kill spid來幹掉(即破壞死鎖的第四個必要條件:循環等待);當然這只是一種臨時解決方案,我們總不能在遇到死鎖就在用戶的生產環境上排查死鎖、Kill sp,我們應該考慮如何去避免死鎖。

(2). 使用SET LOCK_TIMEOUT timeout_period(單位爲毫秒)來設定鎖請求超時。默認情況下,數據庫沒有超時期限(timeout_period值爲-1,可以用SELECT @@LOCK_TIMEOUT來查看該值,即無限期等待)。當請求鎖超過timeout_period時,將返回錯誤。timeout_period值爲0時表示根本不等待,一遇到鎖就返回消息。設置鎖請求超時,破環了死鎖的第二個必要條件(請求與保持條件)。

服務器: 消息 1222,級別 16,狀態 50,行 1
已超過了鎖請求超時時段。

(3). SQL Server內部有一個鎖監視器線程執行死鎖檢查,鎖監視器對特定線程啓動死鎖搜索時,會標識線程正在等待的資源;然後查找特定資源的所有者,並遞歸地繼續執行對那些線程的死鎖搜索,直到找到一個構成死鎖條件的循環。檢測到死鎖後,數據庫引擎 選擇運行回滾開銷最小的事務的會話作爲死鎖犧牲品,返回1205 錯誤,回滾死鎖犧牲品的事務並釋放該事務持有的所有鎖,使其他線程的事務可以請求資源並繼續運行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章