關於資料庫死鎖問題的解釋

itscrambler發表於2012-02-02

在監控程式查詢線上資料時,發現出現如下異常:

com.microsoft.sqlserver.jdbc.SQLServerException: 事務(程式 ID 183)與另一個程式被死鎖在 鎖 資源上,並且已被選作死鎖犧牲品。請重新執行該事務。

[@more@]at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.doExecuteStatement(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement$StmtExecCmd.doExecute(Unknown Source)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(Unknown Source)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeQuery(Unknown Source)

......

網上查詢了一下,原因分析如下:

事務(程式 ID %1!)與另一個程式已被死鎖在資源 {%2!} 上,且該事務已被選作死鎖犧牲品

事務(程式 ID %1!)與另一個程式已被死鎖在資源 {%2!} 上,且該事務已被選作死鎖犧牲品
錯誤 1205嚴重級別 13訊息正文

事務(程式 ID %1!)與另一個程式已被死鎖在資源 {%2!} 上,且該事務已被選作死鎖犧牲品。請重新執行該事務。

解釋

當 Microsoft® SQL Server™ 遇到死鎖時發生該錯誤。當兩個(或多個)程式試圖訪問某個資源,而該資源上有另一個程式控制的鎖時,發生死鎖。因為每個程式都有對另一個資源的請求,所以各程式都不能完成。當檢測到死鎖時,SQL Server 將處理時間最少的命令回滾,並向客戶端應用程式返回錯誤資訊 1205。該錯誤不是嚴重錯誤,且不會導致批處理終止。

對策事務(程式 ID %1!)與另一個程式已被死鎖在資源 {%2!} 上,且該事務已被選作死鎖犧牲品

在某些情況下,死鎖條件將導致 DB-Library 函式(如 dbsqlexecdbsqlokdbresultsdbnextrow)返回 FAIL。程式應該始終檢查從每個 DB-Library 函式返回的程式碼。如果這些 DB-Library 函式之一返回 FAIL,則程式應取消批處理並停止執行。在某些情況下,繼續執行批處理中的後續函式是有可能的。但是,因為發生了死鎖情況並且回滾了引起死鎖的函式,所以批處理中的後續函式將可能因更嚴重的錯誤(如"沒有找到物件")而失敗。

在其它情況下,死鎖條件不會導致 DB-Library 函式返回 FAIL。在這些情況下,程式必須在訊息處理程式中檢查是否有錯誤資訊 1205,並使用dbsetuserdata 函式將此資訊告知應用程式。然後程式必須在每個 DB-Library 呼叫之後檢查是否有死鎖指示符,如果檢測到死鎖則應取消批處理。

儘管在收到 1205 死鎖訊息後取消批處理可能似乎沒有必要,但因為伺服器並不總是終止死鎖情況下的批處理,所以這確實必要。如果未取消批處理,則任何時候試圖提交新的批處理時均將導致 DB-Library 錯誤 10038"結果掛起"。

還可以使用 SET DEADLOCK_PRIORITY 語句(LOW 或 NORMAL)。SET DEADLOCK_PRIORITY 控制在發生死鎖情況時會話的反應方式。如果設定為 LOW,則程式將成為死鎖情況下的首選犧牲品。如果設定為 NORMAL,則會話將使用預設的死鎖處理方法。

如果死鎖情況持續,則使用跟蹤標記 1204 收集更多資訊通常很有用。跟蹤標記 1204 列印死鎖鏈和犧牲品,如以下示例輸出所示:

*** Deadlock Detected *** ==> Process 7 chosen as deadlock victim == Deadlock Detected at: 1998-09-10 16:39:29.17 == Session participant information: SPID: 7 ECID: 0 Statement Type: UPDATE Input Buf: update t1 set c1 = c1 where c1 = 2 SPID: 8 ECID: 0 Statement Type: UPDATE Input Buf: update t1 set c1 = c1 where c1 = 1 == Deadlock Lock participant information: == Lock: KEY: 2:117575457:1 (010001000000) Database: tempdb Table: t1 Index: i1 - Held by: SPID 7 ECID 0 Mode "S" - Requested by: SPID 8 ECID 0 Mode "X" == Lock: KEY: 2:117575457:1 (020002000000) Database: tempdb Table: t1 Index: i1 - Held by: SPID 8 ECID 0 Mode "S" - Requested by: SPID 7 ECID 0 Mode "X"

此死鎖資訊可以解釋如下:

第一部分顯示死鎖犧牲品、死鎖時間以及死鎖中涉及的會話。對於每個會話,顯示當前的 SPID、語句型別和輸入緩衝區的一部分。

第二部分顯示有關死鎖中涉及的鎖的詳細資訊。從上面的輸出,注意死鎖涉及表 t1(索引 i1)上的鍵鎖。死鎖輸出顯示哪些程式擁有死鎖中涉及的鎖,哪些會話在等待鎖被授權以及相關聯的鎖模式。

根據預設,生成最小日誌量的程式將選作死鎖犧牲品,並自動回滾。若要影響所回滾的會話,請為會話設定 DEADLOCK_PRIORITY。

出現這個問題首先要考慮資料庫設計的問題,檢查會不會由於迴圈鎖引起死鎖的問題,即關係互相依賴;第二就要檢查程式的問題,作為資料庫sa我認為應該從這三方面來檢查問題。

1、執行:

dbcc traceon (1204, 3605, -1)
go
dbcc tracestatus(-1)
go

目的是把鎖資訊寫到日誌上(../log/Errlog)檔案上,以檢查分析鎖的產生;

注: 有關DBCC的介紹我會另外寫一篇文章介紹

2、設定lock_timeout變數的時間

select @@lock_timeout (查詢當前設定)

set lock_timeout 1800 (設定當前會話的當前鎖超時設定,單位為毫秒)

這個應該和程式開發人員商量,嵌入在程式裡。 (未做過,待測試:))

3、設定DEADLOCK_PRIORITY變數 控制在發生死鎖情況時會話的反應方式。具體請檢視聯機文件。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26273052/viewspace-1057257/,如需轉載,請註明出處,否則將追究法律責任。

相關文章