1

我有一个通知表,其中包含 id、type、user_id 和 unseen 列。

要获得新的通知计数,我使用:

SELECT count(1) 
FROM notifications 
WHERE user_id=123 AND unseen=1

为了只标记新通知,我使用:

UPDATE notifications 
SET unseen=0 
WHERE user_id=123 AND unseen=1

但是这个更新查询有时会出错。我想知道,这样做的正确方法是什么?

编辑:

ERROR DESC
Transaction (Process ID 68) was deadlocked on lock; 与另一个进程通信缓冲区资源,并已被选为死锁牺牲品。重新运行事务。

4

3 回答 3

0

这可能是死锁问题,当您尝试更新记录时,有些人也在读取这些记录。

您的更新语句是一个完整的语句,我认为它没有在事务中运行。看来,您希望获得更多优先级来完成更新的语句而不是读取语句(使用 select)。

对于上述场景,您可以通过在读取时使用 NoLock 来允许幻读(每次用户使用执行选择查询时得到不同的输出)。在您的场景中,这不是脏读,因为您将只读取已提交的记录。

SELECT count(1) FROM notifications (NOLOCK) WHERE user_id=123 AND unseen=1
于 2012-05-03T13:55:29.353 回答
0

以下语句将忽略锁定的记录和未提交的记录。

SELECT count(1) 
FROM notifications WITH(READPAST)  
WHERE user_id=123 AND unseen=1

以下语句将锁定需要更新的记录,它不会锁定整个表。

UPDATE notifications  with (ROWLOCK) 
SET unseen=0 
WHERE user_id=123 AND unseen=1

所以使用 READPAST 和 ROWLOCK 提示,可以避免死锁。

从她那里阅读以了解 READPAST 和 NOLOCK

于 2012-05-04T11:56:19.863 回答
-1

在“更新”中,您应该使用记录的主键之类的东西来标记您看到的记录。

UPDATE notifications SET unseen=0 WHERE user_id=123 AND unseen=1 and PKID='some thing'
于 2012-05-03T06:41:53.480 回答