處理交易
交易接收方
交易接收者和非交易接收者之間的主要差異在於交易接收者會建立和使用明確的 MSDTC 交易,以確保其資料來源與 BizTalk Server MessageBox 資料庫之間的不可部分完成性。 就配接器的其他部分而言,通常都是相同的。
應注意的是,要求-回應接收配接器只有在提交原始要求訊息至傳訊引擎時才會使用交易。 從傳訊引擎傳送至配接器的回應傳輸必須使用不同的交易。 這是因為第一個交易的範圍是介於配接器與 MessageBox 資料庫之間。 後續的要求訊息要等到原始要求訊息的交易認可後,才會從傳訊引擎傳送至配接器。
底下的物件互動示意圖說明交易式提交內送訊息期間,配接器與傳訊引擎之間的互動。 在此範例中,會依序發生下列互動:
配接器從引擎取得新批次。
配接器建立新的 MSDTC 交易。
配接器對已經登錄於交易中的資料來源進行破壞性讀取。
配接器提交訊息。
配接器會在批次上呼叫 Done ,並傳入其 MSDTC 交易及其 BatchComplete 回呼指標。 引擎會傳回 IBTDTCCommitConfirm 介面。
引擎會處理批次、在其 BatchComplete 實作上重新呼叫配接器,並將訊息處理的狀態傳達給配接器。
如果批次成功,配接器會認可交易,並使用表示認可的值呼叫 IBTDTCCommitConfirm.DTCCommitConfirm API
true
。
交易傳輸器
交易配接器絕大部分都和非交易配接器非常相似。 主要的差異,在於交易配接器會將訊息中的資料傳送至已經登錄於 MSDTC 交易中的資源。
實作提示: 若為交易傳送,配接器應該使用相同的 MSDTC 交易將資料寫入目的地,並透過 IBTTransportBatch.DeleteMessage 方法呼叫加以刪除。 只需要交易這兩項作業即可。 任何其他作業,例如 IBTTransportBatch.Resubmit、 IBTTransportBatch.MoveToNextTransport和 IBTTransportBatch.MoveToSuspendQ 不需要交易。 這是因為引擎會隱含地使用交易,而這些作業類型對目的地而言,不必是不可部分完成的。
底下的物件互動示意圖說明配接器與引擎之間的互動。 事件順序如下:
引擎從配接器取得新的批次。
引擎將兩個訊息加入至新批次。
引擎會在批次上呼叫 Done ,讓配接器將批次張貼到其執行緒集區所服務的內部傳輸佇列。
配接器建立新的 MSDTC 交易。
配接器傳輸訊息,將目的地登錄在 MSDTC 交易中。 例如,這可能會寫入SQL Server資料庫。
在傳輸之後,配接器從引擎取得新的批次。
配接器會針對已成功傳輸的訊息呼叫 DeleteMessage 。
配接器會在批次上呼叫 Done ,以傳入其 DTC 交易。 引擎會傳回 IBTDTCCommitConfirm 介面。
引擎處理該批次並從應用程式佇列刪除訊息。
引擎會回呼配接器的 IBTBatchCallback 介面,其中包含刪除作業成功的相關資訊。
如果批次成功,配接器隨即認可交易。
配接器會呼叫 IBTDTCCommitConfirm.DTCCommitConfirm ,以通知引擎已成功認可交易。
交易請求-回應配接器
與雙向接收不同,雙向傳送可以使用同一筆 DTC 交易來執行。 Transacted solicit-response 配接器應該針對SubmitResponseMessage和DeleteMessage作業使用相同的IBTTransportBatch。 這個批次應該使用與用於傳送和接收請求-回應訊息組相同的 MSDTC 交易。 這樣可以確保「請求-回應訊息交換」的不可部份完成性。
服務元件和 BYOT
使用傳訊引擎 API 時,必須提供 MSDTC 交易。 但有些 .NET 元件是設計用來當做服務元件,不允許透過程式設計方式認可或中止交易, 而是由該平台上的 COM+ 執行階段自動認可交易。
在這些實例中,配接器應該使用 Bring Your Own Transaction (BYOT)。 這可以讓配接器建立 MSDTC 交易、產生使用交易的 .NET 元件,以及允許該元件繼承已建立的交易而不要建立它自己的交易。 .NET Framework為此目的提供System.EnterpriseServices.BYOT。 SDK BaseAdapter 會為此目的提供協助程式類別 BYOTTransaction。
避免競爭條件
當您撰寫建立交易對象的配接器,並將它交給BizTalk Server時,您必須負責撰寫執行下列動作的程式碼:
在與批次關聯的訊息中解決錯誤。
決定與批次作業關聯之交易的最後結果。
配接器必須通知BizTalk Server交易的最終結果,以維護其內部追蹤資料。 配接器會呼叫DTCConfirmCommit來通知BizTalk Server結果。 如果配接器不這麼做,就會發生嚴重的記憶體遺漏。
上述兩項工作 (解決錯誤,並決定最終結果) 看起來很簡單,但事實上,它們依賴不同執行緒的資訊:
配接器會根據BizTalk Server傳遞至配接器中BatchComplete回呼的資訊來處理錯誤。 這個回呼位於配接器的執行緒上。
DTCConfirmCommit 是 IBTDTCCommitConfirm 物件上的方法。 IBTDTCCommitConfirm物件的實例是由批次IBTTransportBatch::D one呼叫所傳回。 這個實例位於與 IBTTransportBatch::D one 呼叫相同的執行緒上,這與配接器的執行緒不同。
對於介面卡對 IBTTransportBatch::D one 的每個呼叫,都會有對應的回呼 BatchComplete,該回呼是由傳訊引擎在不同的執行緒中呼叫,以報告批次提交的結果。 在 BatchComplete 中,配接器必須根據批次通過或失敗來認可或回復交易。 不論是哪一種情況,介面卡都應該呼叫 DTCConfirmCommit ,向傳訊引擎報告交易的狀態。
可能的競爭條件存在,因為配接器的BatchComplete實作可以假設IBTDTCCommitConfirm物件在BatchComplete執行時永遠可以使用IBTTransportBatch::D one。 不過,即使在IBTTransportBatch::D one傳回之前,您也可以在不同的傳訊引擎執行緒中呼叫BatchComplete。 當介面卡嘗試存取 IBTDTCCommitConfirm 物件作為 BatchComplete 實 作的一部分時,可能會發生存取違規。
在下列範例中,將使用事件來解決問題。 這裡會使用事件的屬性來存取介面指標。 Get 方法永遠會等候 Set 方法完成。
protected IBTDTCCommitConfirm CommitConfirm
{
set
{
this.commitConfirm = value;
this.commitConfirmEvent.Set();
}
get
{
this.commitConfirmEvent.WaitOne();
return this.commitConfirm;
}
}
protected IBTDTCCommitConfirm commitConfirm = null;
private ManualResetEvent commitConfirmEvent = new ManualResetEvent(false);
現在,將 IBTTransportBatch::D one 的傳回值指派給此屬性,並在 BatchComplete 呼叫中使用它。