SQL Server进程队列竞争条件

Wil*_*son 44 sql t-sql sql-server 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
Run Code Online (Sandbox Code Playgroud)

gbn*_*gbn 56

编辑:

我用谷歌搜索我的答案:"使用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
Run Code Online (Sandbox Code Playgroud)

刷新,2011年10月

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

  • @NelsonRothermel:是的,因为否则它是2个进程可以读取的共享/读取锁,而READPAST将不起作用 (3认同)

A-K*_*A-K 6

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

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