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

根据死锁图,当多个客户端同时连接时会导致死锁。

我不明白为什么这会导致死锁,
我什至不明白为什么该查询需要锁。
我究竟做错了什么?

4

2 回答 2

1

在插入之前每次更新 EndDate 似乎不是一个好主意。即使没有完成更新,您也可能会锁定表。您应该在更新之前检查给定客户端的 endate 是否为空的任何会话。您可以使用 NoLock 提示读取未提交的数据。

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

于 2013-05-01T15:29:21.110 回答
1

好吧,更新语句会产生 X 锁,因为该语句甚至可能是页锁或表锁,您可以尝试选择打开会话的 id 并在之后使用 in-clause 执行更新,即更有可能只锁定那些行。这也取决于您的隔离级别。

方式不能打开多个会话,如果(我猜它是一个 Web 应用程序)用户使用 2 个不同的 Web 浏览器打开该站点怎么办。

于 2013-05-01T15:07:13.740 回答