2011-12-30 43 views
3

我的过程如下:我应该如何从数据库表中实现多线程队列?

  1. 用户登录到Web应用程序,这降低了进入UserQueue表
  2. Windows服务调查此表每x秒和处理每个项目
  3. 一旦处理项目从UserQueue表

这一切工作很好地顺序处理,但我担心的是一个长时间运行的任务可以阻止所有其他用户的队列中删除(这将是Web应用程序的问题)。

我认为.NET中的BlockingCollection可以将内容保存在内存中,然后处理它们,但我无法保证UserQueue表中的行不会多次放入该集合中(由于非唯一BlockingCollection的性质),除非我使用数据库标志(例如BeingProcessed = true)。我不喜欢数据库标志,因为如果我的服务因任何原因被停止,它可能会在表中存在未处理的项目,其中BeingProcessed = true。

有没有更多的标准方法来解决这个问题,我错过了,或者我应该考虑Quartz.net还是类似的?

+0

此答案可能会对您有所帮助:[http://stackoverflow.com/questions/2177880/using-a-database-table-as-a-queue](http://stackoverflow.com/questions/2177880/using -a-database-table-as-a-queue) – 2011-12-30 21:44:23

+1

更标准的方法是使用适当的消息队列(比如msmq)。我认为你的做法被称为贫民窟队列。 – keni 2011-12-30 21:45:36

+0

同上@keni。 [RabbitMQ](http://www.rabbitmq.com/devtools.html#dotnet-dev)特别容易设置和使用。 – TrueWill 2011-12-30 21:59:15

回答

1

基本技巧是使用测试和设置与日期,而不是一个简单的布尔值。以下是你如何做到这一点。

假设你的UserQueue表非常简单。类似这样的,目前:

create table UserQueue (id integer primary key, description varchar not null) 

到目前为止,这么好。但是我们想要安全地抓住一项任务,并且做一些事情。

首先,让我们改变轻微的模式:

create table UserQueue (id integer primary key, description varchar not null, 
         dtLocked datetime null) 

现在,我们只需按照一个简单直接的方法:

  1. 找事,我们可以通过select * from UserQueue limit 1
  2. 要求尝试锁定它,将时间戳设置为NOW(),其中它当前为空通过例如update UserQueue set dtLocked = NOW() where id = @id and dtLocked is null
  3. 只有在至少更新了一行时才会继续。

因为我们现在正在使用datetime的锁,我们就可以通过简单的update语句经常用于删除的时间超过—一定量年长锁说五分钟清理死任务。

作为奖励,此设计可以让您一次安全地处理多个任务,因此您可以通过简单地启动更多线程来消除任何阻止用户任务的机会。

+0

谢谢Benjamin - 这是一个很好的解决方案,可以在不改变架构的情况下快速解决这个问题。我开始质疑自己处理队列,因为它被肯尼称为贫民窟队列;-) – petenelson 2011-12-31 10:44:15

+0

为了摆脱我们的贫民窟队列在这个时候对我们来说是不正确的 - 我探索了所有其他的选择,但本杰明的解决方案工作最适合我们 - 非常感谢!我还加入了机器名称列,以便我可以查看哪台机器正在处理队列中的项目,以便我可以根据需要使用更多机器扩展它 – petenelson 2012-01-03 16:04:39

0

虽然您的问题可能会从数据库事务中受益,但我不确定在排队的相同项目中长时间运行的进程会获得多少收益。对于这种情况,我会建议找到一个更好的主键,这对提交的数据有意义,以便影响该行的数据将由排队框架按顺序应用。我还建议寻找像Microsoft Queuing或IBM MQ这样的现有排队框架(我承认我不是很熟悉排队框架)。