【问题标题】:SQL Server Process Queue Race ConditionSQL Server 进程队列竞争条件
【发布时间】:2010-10-30 16:52:26
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

    编辑:

    我用谷歌搜索了我的答案:"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 子句更优雅地完成此操作。

    【讨论】:

    • 有趣...我会试试看
    • 添加额外的提示真的很有帮助。不再重复。谢谢。
    • 我知道这是旧的,但UPDATE 语句中的UPDLOCK 提示是否在读取 要更新的行时强制更新锁(而不是共享锁)?换句话说,如果你不使用UPDLOCK,是否有可能存在竞争条件并且两个更新语句选择相同的行?
    • @NelsonRothermel:是的,因为否则它是共享/读取锁,2 个进程可以读取并且 READPAST 将不起作用
    • @UriAbramson 这是一个猜测,但如果不使用 ROWLOCK,那么进程 1 会更新 20 行但锁定超过 20 行(例如 40 行)。进程 2 更新 20 行但跳过 40 行。因此将错过 20 行! ROWLOCK 表示仅锁定更新的行。
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2019-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-14
      • 1970-01-01
      相关资源
      最近更新 更多