SQL Server进程队列竞争条件
我有一个订单队列,由多个订单处理程序通过存储过程访问。每个处理器传入一个唯一的ID,该ID用于锁定接下来的20个订单供自己使用。然后,存储过程将这些记录返回给订单处理器,以便对其执行操作 在某些情况下,多个处理器能够检索同一个“OrderTable”记录,,此时他们试图同时对该记录进行操作。这最终会导致在流程的后期抛出错误 我的下一步行动是允许每个处理器获取所有可用的订单,并循环处理处理器,但我希望简单地使这部分代码线程安全,并允许处理器随时获取记录 所以明确地说——任何关于我为什么会经历这种比赛状态以及如何解决这个问题的想法SQL Server进程队列竞争条件,sql,sql-server,tsql,queue,race-condition,Sql,Sql Server,Tsql,Queue,Race Condition,我有一个订单队列,由多个订单处理程序通过存储过程访问。每个处理器传入一个唯一的ID,该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
编辑:
我用谷歌搜索了一下我的答案:。我已经有好几年没有读过这个解决方案了
原件:
如果使用READPAST提示,则将跳过锁定的行。您使用了ROWLOCK,因此应该避免锁升级。我发现你也需要升级锁
因此,进程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月
如果您需要一次选择和一次更新,那么可以使用OUTPUT子句更优雅地完成此操作。您可以使用ServiceBroker。您还可以使用sp_getapplock序列化对行的访问—这将消除争用条件: “通过创建自己的锁(SQL中的互斥锁)来协助并发”
很有趣……我将尝试添加一些真正有用的额外提示。不再重复。谢谢。我知道这很旧,但是
UPDATE
语句中的UPDLOCK
提示是否在读取要更新的行时强制更新锁(而不是共享锁)?换句话说,如果不使用UPDLOCK
,是否可能存在争用条件和两个update语句来选择相同的行?@NelsonRothermel:是的,因为否则它是共享/读取锁,两个进程可以读取,而readpass不会work@UriAbramson这只是猜测,但如果不使用ROWLOCK,然后进程1更新20行,但锁定超过20行(例如40行)。进程2更新20行,但跳过40行。因此,将错过20行!ROWLOCK表示仅锁定已更新的行。