44

我有一个订单队列,多个订单处理器通过存储过程访问该队列。每个处理器传入一个唯一 ID,用于锁定接下来的 20 个订单以供自己使用。然后存储过程将这些记录返回给订单处理器以进行操作。

在某些情况下,多个处理器能够检索相同的“OrderTable”记录,此时它们会尝试同时对其进行操作。这最终会导致在流程后期抛出错误。

我的下一步行动是让每个处理器获取所有可用订单并循环处理处理器,但我希望简单地使这部分代码线程安全并允许处理器随时获取记录。

如此明确-知道为什么我会遇到这种竞争状况以及如何解决问题。

BEGIN TRAN
    UPDATE  OrderTable WITH ( ROWLOCK )
    SET     ProcessorID = @PROCID
    WHERE   OrderID IN ( SELECT TOP ( 20 )
                                        OrderID
                                FROM    OrderTable WITH ( ROWLOCK )
                                WHERE   ProcessorID = 0)
COMMIT TRAN


SELECT  OrderID, ProcessorID, etc...
FROM    OrderTable
WHERE   ProcessorID = @PROCID
4

2 回答 2

61

编辑:

我用谷歌搜索了我的答案:“使用 READPAST 和 UPDLOCK 处理 SQL Server 中的数据队列”。自从我阅读并使用此解决方案以来已经有好几年了。

原来的:

如果您使用 READPAST 提示,则会跳过锁定的行。您已经使用了 ROWLOCK,因此您应该避免锁升级。正如我发现的那样,您还需要 UPDLOCK。

所以进程 1 锁定 20 行,进程 2 将占用接下来的 20 行,进程 3 将占用第 41 到 60 行,依此类推

更新也可以这样写:

UPDATE TOP (20)
    foo
SET
    ProcessorID = @PROCID
FROM
    OrderTable foo WITH (ROWLOCK, READPAST, UPDLOCK)
WHERE
    ProcessorID = 0

刷新,2011 年 10 月

如果您需要一次执行 SELECT 和 UPDATE,则可以使用 OUTPUT 子句更优雅地完成此操作。

于 2009-06-02T14:51:22.517 回答
6

您可以使用服务代理。您还可以使用 sp_getapplock 序列化对行的访问 - 这将消除竞争条件:

“通过创建自己的锁(SQL 中的互斥锁)来辅助并发” http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/06/30/855.aspx

于 2009-06-02T15:21:45.280 回答