2012-09-25 41 views
4

我想使用SQL Server事件探查器來識別死鎖的原因。 這裏的僵局圖: Deadlock graph 兩個陳述都是插入其次是select scope_identity(); 其實一個有2個併發流程,反覆做嵌入select_identity在一個週期。SQL服務器事件探查器中的死鎖圖顯示相同的集羣密鑰上的相互鎖

我希望那是什麼插入採取排它鎖在聚集索引選擇採取非聚集索引的共享鎖,然後他們等待對方釋放它們各自的的indeces。

我看到的是兩個進程等待釋放相同的資源 - 聚集索引。怎麼會這樣?特別追索權應屬於一個進程或另一進程。我在這裏想念什麼?感謝所有提前。

編輯:是的,隔離級別是Serializible。 PS:也許,我的關於非聚集索引的共享鎖的假設是錯誤的,只要我的選擇不包含where聲明

EDIT2: 這裏是XML的一部分:

<resource-list> 
    <keylock hobtid="72057594148028416" dbid="29" objectname="<confidential>" indexname="PK_WP_Inbound_StockTransactionLine" id="lock9641700" mode="RangeS-S" associatedObjectId="72057594148028416"> 
    <owner-list> 
    <owner id="process8e09288" mode="RangeS-S"/> 
    </owner-list> 
    <waiter-list> 
    <waiter id="process991ce08" mode="RangeI-N" requestType="convert"/> 
    </waiter-list> 
    </keylock> 
    <keylock hobtid="72057594148028416" dbid="29" objectname="<confidential>" indexname="PK_WP_Inbound_StockTransactionLine" id="lock9641700" mode="RangeS-S" associatedObjectId="72057594148028416"> 
    <owner-list> 
    <owner id="process991ce08" mode="RangeS-S"/> 
    </owner-list> 
    <waiter-list> 
    <waiter id="process8e09288" mode="RangeI-N" requestType="convert"/> 
    </waiter-list> 
    </keylock> 
    </resource-list> 

據此,我認爲這是範圍掃描引起的SERIALIZABLE隔離(谷歌搜索引擎)。但是,我不明白這是怎麼發生的,建議的補救措施是什麼。

+0

你正在使用什麼隔離級別?序列化?如果是這樣的原因? –

+0

是的,我忘了說,對不起。我編輯了帖子 –

+0

發佈死鎖XML,而不是圖像。圖像不完整,誤導而且往往是錯誤的。 –

回答

5

考慮以下代碼從兩個並行事務(T1和T2)中訪問相同的記錄。

Read LastRow 
Insert AtLastRow 

假設上下文切換髮生在Read。所以操作順序是

T1 Read LastRow 
T2 Read LastRow 
T2 Insert AtLastRow // This will wait for T1 to finish. 
T1 Insert AtLastRow // This will wait for T2 to finish. Hence deadlock! 

上面的讀取會帶上Range S-S鎖定。最後插入還需要Range I-N,這與其他交易持有的鎖現有的Range S-S不兼容。因此它等待。

可以有多種方法來解決這個問題。

  1. 使用讀提交作爲整體隔離級別和不可序列化。 這將防止取得範圍鎖定。
  2. 閱讀更新鎖(UPDLOCK)。這將獨家更新 鎖定在第一位。因此其他交易將在閱讀本身等待。
  3. 避免讀取和插入/更新模式。直接插入/更新 ,讓它失敗。

讓我知道如果您有任何問題。

+0

3.避免讀取和插入/更新模式。那我該如何處理失敗?即。如果記錄已經存在,我需要做別的事情(比如說,顯示一個特定的消息)。我應該只是w8例外嗎?然後什麼?解析異常數據以確定其確切原因?另外,爲什麼要插入/更新失敗?考慮一種情況,我需要檢查業務邏輯約束,而不是數據模型約束。可能的解決方案也是將讀操作移出事務處理。但在我們的情況下,這是2%的重構,所以我將改變隔離級別作爲解決方法。謝謝=) –

+0

@ArturUdod讓你說讀一行key = 10並增加值。您可以讀取該值並更新它,或者繼續並更新。如果密鑰不存在,則上述更新將失敗。現在,如果您檢測到失敗,則將值爲1的鍵10插入。這有幫助嗎? – Ankush

+0

是的,我明白了。但是,正如我所說:讓我們假設我只想增加一個值,如果它小於100.如果它已經是100,那麼我想顯示一條消息。關閉源,可以有一個「檢查」約束,但這是一個簡單的例子。我可能有更復雜的驗證業務邏輯,我實際上需要在修改數據之前執行讀取操作。 –