代码之家  ›  专栏  ›  技术社区  ›  Gabe Moothart

自动标记并返回数据库中的一组行

  •  6
  • Gabe Moothart  · 技术社区  · 16 年前

    我正在编写一个后台服务,它需要处理一系列作业,这些作业作为记录存储在sqlserver表中。服务部门需要找到最早的20个需要工作的工作( where status = 'new' 标记它们( set status = 'processing' ,运行它们,然后更新作业。

    这是我需要帮助的第一部分。可能有多个线程同时访问数据库,我想确保“mark&return”查询以原子方式运行,或者几乎是以原子方式运行。

    这个服务将花费相对较少的时间访问数据库,如果一个作业运行两次,这不是世界末日,因此为了提高代码的简单性,我可能能够接受一小部分作业运行多次的可能性。

    最好的方法是什么?我正在为我的数据层使用linq-to-sql,但我想为此我必须下拉到t-sql中。

    5 回复  |  直到 16 年前
        1
  •  10
  •   Remus Rusanu    16 年前

    您的作业表是一个队列。写用户表备份的队列是一个众所周知的错误,因为它会导致死锁和并发问题。

    最简单的方法是删除用户表并使用 queue 相反。这将使您在经过系统测试和验证的代码库上获得无死锁、无并发的队列。问题是,队列的整个范式从插入和删除/更新变为 SEND / RECEIVE . 另一方面,对于内置队列,您可以获得一些非常强大的免费商品,即 Activation correlated items locking .

    如果要继续沿着用户表备份队列的路径运行,则 第二 编写用户表队列的最重要技巧是使用更新…输出:

    WITH cte AS (
      SELECT TOP(20) status, id, ...
      FROM table WITH (ROWLOCK, READPAST, UPDLOCK)
      WHERE status = 'new'
      ORDER BY enqueue_time)
    UPDATE cte
      SET status = 'processing'
    OUTPUT
      INSERTED.id, ...
    

    CTE语法只是为了方便正确地放置top和order by,查询可以使用派生表编写,就像ESILY一样。不能直接更新…顶部,因为更新不支持订单,并且您需要它来满足您需求的“最早”部分。需要锁提示来促进并行处理线程之间的高并发性。

    我说这是第二个最重要的技巧。最重要的是如何组织表格。要排队 必须 被群集 (status, enqueue_time) .如果不正确地组织表,最终会出现死锁。先发制人的评论:在这种情况下,碎片化是不相关的。

        2
  •  8
  •   Community Mohan Dere    9 年前

    请看我的答案: SQL Server Process Queue Race Condition 它还可以一次管理20行。

    基本上,在SQL Server中,使用提示rowlock、readpass和updlock管理并发性和轮询非常简单。

    我不能对Linq发表评论,但是事务仍然会使您面临并发问题:您需要使用我提到的提示

        3
  •  4
  •   Community Mohan Dere    9 年前

    建立在 gbn's answer

    如果使用的是SQL Server 2005或更高版本,则可以使用 OUTPUT clause 在你 UPDATE 声明:

    UPDATE TOP (20) your_table
    SET status = 'processing'
    OUTPUT INSERTED.*
    FROM your_table WITH (ROWLOCK, READPAST, UPDLOCK)
    WHERE status = 'new'
    
        4
  •  1
  •   Stéphane    16 年前

    我知道这不是主题,但您可以使用msmq。消息队列会将您的作业按顺序排列,并且是线程安全的。您还可以在msmq管理自身时分配优先级。您可以使用read或peek从队列中删除消息,或者只查看其中的内容。您可以使用命令设计模式来帮助您实现这一点。

        5
  •  0
  •   birdus    16 年前

    它不仅仅像在事务中运行T-SQL那样简单,还是我遗漏了一些东西?