2011-12-30 53 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這樣的現有排隊框架(我承認我不是很熟悉排隊框架)。

相關問題