2

我有保存客戶端的連接和斷開時間的表。如何避免簡單更新語句的死鎖?

ID  int 
ClientID int 
BeginDate datetime 
EndDate datetime 

當客戶端連接,一個Session記錄與其EndDate創建爲空。

INSERT Session(ClientID, BeginDate, EndDate) 
VALUES(@ClientID, GETDATE(), null) 

當客戶端斷開時,我更新會話所以它的EndDate包含斷開連接的時間。

UPDATE Session 
SET EndDate = GETDATE() 
WHERE Id  = @SessionID 

但是這並不總是被調用。

因此,爲了確保同一客戶端同時沒有多個會話,我在插入新會話之前運行此查詢。

UPDATE Session 
SET EndDate  = GETDATE() 
WHERE ClientID = @ClientID 
and EndDate  is null 

當多個用戶在同一時間連接,根據deadlock graph從而導致死鎖。

我不明白爲什麼這會導致死鎖,
我甚至不明白爲什麼該查詢需要鎖定。
我在做什麼錯?

回答

1

每次插入之前更新EndDate似乎不是一個好主意。即使沒有更新完成,您也可以鎖定表格。在更新之前,您應該檢查給定客戶端是否有任何endate爲null的會話。您可以使用NoLock提示來讀取 未提交的數據。

執行此檢查將最大限度地減少此查詢造成的鎖定。預防好,然後治癒:)

+0

+1,我現在只需選擇ID(with(nolock)''並且只在需要時更新表。它像一個魅力工作,謝謝。 – 2013-05-02 07:01:01

1

良好的更新語句使X鎖,這個說法甚至是一個網頁或廣告表鎖,你可以嘗試選擇打開的會話ID和執行這些更新與在子句後那更可能只鎖定那些行。它也取決於你的隔離級別。

方式不能有多個會話打開,如果(並且我猜測它是一個web應用程序)用戶使用兩個不同的web瀏覽器打開該網站。

+0

+1,謝謝。死鎖圖表明,這是一個頁面鎖,是的,選擇ID第一次工作。我接受了ARS的答案,因爲他的'nolock'建議。在使用之前,'select'查詢也會導致死鎖。關於會話,它不是一個網站,這是一個Windows服務,我們的GPRS設備連接,這樣一臺設備不能同時連接多次。 – 2013-05-02 07:03:45