如何避免简单更新语句的死锁?

时间:2013-05-01 14:41:25

标签: sql-server asynchronous sql-update relational-database database-deadlocks

我有一个表,用于保存客户端的连接和断开连接时间。

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,当多个客户端同时连接时会导致死锁。

我不明白为什么会导致死锁, 我甚至不明白为什么这个查询需要锁定 我做错了什么?

2 个答案:

答案 0 :(得分:1)

一个更新语句使得X锁定,对于这个语句甚至可能是一个页面锁定或一个表锁定,您可以尝试选择打开会话的id并使用in执行这些更新-clause之后,更有可能只锁定那些行。这也取决于你的隔离级别。

方式不能打开多个会话,如果(并且我猜测它是一个网络应用程序)用户使用2个不同的网络浏览器打开网站。

答案 1 :(得分:1)

每次插入之前更新EndDate似乎不是一个好主意。即使没有更新,您也可以锁定表。在更新之前,您应该检查是否有任何会话,其中endate为null。您可以使用NoLock提示进行阅读 未提交的数据。

执行此检查可以最大程度地减少此查询导致的锁定。预防胜于治疗:)