SQL Server进程队列争用条件

我有一个通过存储过程由多个订单处理器访问的订单队列。 每个处理器传入一个唯一的ID,用于locking下一个20个订单,供自己使用。 存储过程然后将这些logging返回到订单处理器以执行操作。

在某些情况下, 多个处理器可以检索同一个“OrderTable”logging ,并在这个logging上尝试同时对其进行操作。 这最终导致过程中稍后抛出错误。

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

所以明确 – 任何想法,为什么我遇到这种竞争条件,以及如何解决问题。

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 

编辑:

我GOOGLE了检查我的答案: “用READPAST和UPDLOCK处理SQL Server中的数据队列” 。 我阅读了这个解决scheme并且玩了好几年。

原版的:

如果使用READPAST提示,则会跳过locking的行。 你已经使用了ROWLOCK,所以你应该避免锁升级。 你也需要UPDLOCK,因为我发现了。

所以进程1locking了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子句更优雅地完成。

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

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