SQL Server进程队列竞争条件

时间:2009-06-02 14:16:21

标签: sql sql-server tsql queue race-condition

我有一个订单队列,由多个订单处理器通过存储过程访问。每个处理器都传入一个唯一的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

2 个答案:

答案 0 :(得分:55)

编辑:

我用谷歌搜索我的答案:"Processing Data Queues in SQL Server with READPAST and UPDLOCK"。自从我阅读并使用此解决方案以来,已经有好几年了。

原件:

如果使用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子句更优雅地完成此操作。

答案 1 :(得分:6)

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

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