【问题标题】:UPDATE SELECT in LINQ to SQL在 LINQ to SQL 中更新 SELECT
【发布时间】:2010-01-04 00:28:32
【问题描述】:

我正在编写一个多线程服务,该服务会挑选状态为 1(未处理)的作业进行处理。一旦它们被拾取,我需要将这些行的状态更改为 2(表示 In Progress),以便另一个线程(在几秒钟内产生)不会拾取这些行进行处理。

对于选择,我会这样做:

var jobs = from j in db.Jobs
           where j.Status == 1
           select j;

如何重写它以更新行并同时选择它们?

【问题讨论】:

    标签: .net linq linq-to-sql


    【解决方案1】:

    使用transaction。有一些例子说明它是如何工作的here

    【讨论】:

      【解决方案2】:

      这是典型的队列模式,要正确有效地执行此操作,您必须使用带输出的更新:

      UPDATE TOP (...) table
      SET status = 2
      OUTPUT deleted.*
      WHERE status = 1;
      

      没有等效的 Linq2Sql,对于这个特殊的工作你不应该使用 Linq。只需创建一个存储过程并将其显式添加到您的数据上下文中,然后将返回的类型修改为 Jobs。使用事务,您将无法做到这一点,而不是任何其他构造,甚至会接近使用 UPDATE 和 OUTPUT 的性能。

      我还添加了一个 TOP 子句,这在队列模式中相当常见,每个阅读器为了在负载尖峰中生存而进行有限的工作。

      【讨论】:

        【解决方案3】:

        由于很多线程可能会互相踩踏,最简单的方法是设置另一个字段为当前作业或线程 id:

        update t set runner_id = ? where runner_id = 0
        select * from t where runner_id = ?
        (? = my thread or connection id)
        

        或者您可以使用锁或事务锁定表并执行 2 个查询:选择,然后更新到处理

        【讨论】:

        • 如果我使用锁,我无法在锁块之外使用作业变量。我该怎么做?
        【解决方案4】:

        在您选择之后,我会有一个 foreach,您可以在其中更新值然后提交它们,然后再继续执行程序的其余部分

        foreach (Job j in jobs)
        {
            j.Status = 0;
        }
        db.SubmitChanges()
        

        那么你仍然有你的工作并且数据库已更新......

        【讨论】:

        • 问题是在运行更新时,不同的线程可能已经运行了选择,所以我们有两个不同的线程处理相同的作业两次
        猜你喜欢
        • 1970-01-01
        • 2012-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-02
        • 1970-01-01
        相关资源
        最近更新 更多