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