2012-05-04 21 views
1

我有一些(实体框架4)代码,看起来像这样:从数据库处理队列时替代系统范围的互斥?

class QueueItem{ 
    public bool Processed { get; set; } 
    // ... other fields 
} 

class QueueContext: System.Data.Entity.DbContext 
{ 
    public System.Data.Entity.DbSet<QueueItem> Queue { get; set; } 

    public void ProcessItems() 
    { 
     do 
     { 
      var item = Queue.FirstOrDefault(q => !q.Processed); 
      if(item == null) break; 
      ProcessItem(item); 
      item.Processed = true; 
      SaveChanges(); 
     } while(true); 
    } 

    //... 
} 

我想改变它是多线程的外部ProcessItems方法。实际上,我希望多个进程/应用程序域同时运行此代码。如何让多个进程从队列中选取相同的项目?我可以使用全系统(有名)的互斥锁,但我已经看到这些速度非常慢。我正在寻找某种原子“拉动并标记为正在进行中”。我使用SqlServerCE4作为数据存储。

回答

3

使用像MSMQ,Azure队列甚至Sql Server Service Broker这样的实际消息队列(当然不会与CE一起工作)可能会更好。像Redis这样的东西可能也更容易。如果这些都不是一种选择,你可能需要做类似如下:

  1. 添加“INPROGRESS”字段的表
  2. 确保您为表启用乐观并发(如通过RowVersion)
  3. 当您查询时,查询既不InProgress也不完整的事物
  4. 当您获取第一个实体时,更新InProgress字段以指示您已抓取它并SaveChanges。
  5. 处理并发异常(如果发生的话)。这意味着别人已经在同一时间抓住了这个物品,但他们先救了。在这种情况下,重新启动您的循环并寻找下一个循环。
  6. 如果没有异常被抛出,就像你一样处理,除非你必须使用适当的错误处理来确保InProgress总是被清除,即使在你标记为InProgress之后的某个点抛出异常。