轉自:http://www.cnblogs.com/daxnet/archive/2011/03/15/1984995.htmlhtml
.NET直接提供對MSMQ的訪問支持,只須要添加System.Messaging程序集引用便可方便地操做MSMQ。MSMQ支持兩種事務處理模式:內部事務處理以及基於MS-DTC的分佈式事務處理。數據庫
MSMQ的內部事務處理框架
MSMQ的內部事務處理是指,僅採用MSMQ自己提供的事務處理機制完成事務處理。好比,假設有一系列的消息須要發佈到MSMQ,那麼,就能夠啓動一個內部事務,確保這些消息的發佈過程是一個原子操做。要使用MSMQ的內部事務處理機制,在建立消息隊列的時候,就須要勾選「事務性」選項,以下圖所示:分佈式
首先,須要建立一個MessageQueueTransaction的對象,並使用Begin調用以啓動MSMQ的內部事務處理。而後,在MessageQueue的Send方法中,使用Send(object, MessageQueueTransaction)的重載函數發送消息,將建立好的MessageQueueTransaction對象做爲第二個參數傳遞給Send方法;在完成全部消息的發送以後,使用MessageQueueTransaction對象的Commit方法提交事務。若是在發送消息的過程當中遇到問題,則使用MessageQueueTransaction對象的Abort調用回滾事務。請參見下面的示例代碼:函數
using (MessageQueue messageQueue = new MessageQueue(@".\private$\TPCDemoQueue",
false, false, QueueAccessMode.SendAndReceive))
{
MessageQueueTransaction trans = new MessageQueueTransaction();
try
{
trans.Begin();
for (int i = 0; i < 5; i++)
{
messageQueue.Send(new Message(i), trans);
}
trans.Commit();
}
catch
{
trans.Abort();
}
messageQueue.Close();
}
注意:若是你的消息隊列在建立的時候沒有設置「事務性」選項,那麼,在完成消息隊列的建立之後,你將沒法修改該選項。更糟糕的是,在非事務性隊列上執行上面的代碼,則沒法將消息發佈到消息隊列上,框架自己也不會提示任何錯誤信息,指示消息並未發佈成功。工具
在分佈式事務處理中使用MSMQ性能
在分佈式事務處理的上下文中(好比,.NET 2.0+的TransactionScope中),上面所提到的MessageQueueTransaction將毫無用處,也就是說,MessageQueueTransaction與分佈式事務處理毫無關係。你所要作的是,用正常的方式初始化一個MessageQueue的實例,而後,調用Send方法發佈消息,在發佈消息的時候,經過設置MessageQueueTransactionType的值來告訴MessageQueue,目前正處於一個分佈式事務的上下文中。因而,你須要使用Send/Receive的重載方法:Send(object, MessageQueueTransactionType)以及Receive(MessageQueueTransactionType)。以下:spa
using (TransactionScope transaction = new TransactionScope())
{
Message inputMsg = inputQueue.Receive(MessageQueueTransactionType.Automatic);
// do some work
transaction.Complete();
}
注意:對於一些生命週期相對較長的事務處理,好比,假設你的用例是這樣的:你首先須要從一個消息隊列中得到消息,而後更新你的數據庫記錄,那麼你的代碼可能會是這樣的:3d
using (TransactionScope transaction = new TransactionScope())
{
using (MessageQueue someQueue = new MessageQueue("<queue connection>"))
{
Message msg = someQueue.Receive();
// do something else
}
transaction.Complete();
}
這樣作實際上是不對的!由於Receive方法是一種同步調用,若是消息隊列中根本沒有任何內容,那麼Receive調用就會被阻塞,直到消息隊列中出現新的消息。這就意味着你的分佈式事務一直都是處於開啓的狀態,並且可能因爲等待時間過長而致使超時,最終致使一個MessageQueueException。htm
正確的作法是,在MessageQueue上使用BeginPeek調用(注意:不是BeginReceive方法,由於BeginReceive方法並非用來處理事務性隊列的),而後訂閱PeekComplete事件,在事件處理過程當中,再使用TransactionScope以及Receive等方法實現消息的獲取。例如:
MessageQueue inputQueue = new MessageQueue("<queue connection>");
inputQueue.PeekCompleted += (s, e) =>
{
using (TransactionScope transaction = new TransactionScope())
{
Message inputMsg = inputQueue.Receive(MessageQueueTransactionType.Automatic);
// do some work
transaction.Complete();
}
inputQueue.BeginPeek();
};
inputQueue.BeginPeek();
最後再提醒一下,就是若是你所要作的事情僅限於與MSMQ打交道,那麼只要使用MSMQ的內部事務處理機制就能夠了,畢竟使用分佈式事務處理會涉及到MS-DTC,從而形成過大的系統開銷,影響性能。