トランザクションの処理
トランザクション受信元
トランザクションレシーバーと非トランザクション レシーバーのメイン違いは、トランザクションレシーバーが明示的な MSDTC トランザクションを作成して使用して、データ ソースとBizTalk Server MessageBox データベースの間の原子性を確保することです。 一般に、アダプターのその他の側面はすべて同じです。
要求 - 応答の受信アダプターは、メッセージング エンジンに元の要求メッセージを送信するためにのみ、トランザクションを使用します。 メッセージング エンジンからアダプターに応答が送信されるためには、別のトランザクションが必要です。 これは、最初のトランザクションのスコープが、アダプターとメッセージ ボックス データベースの間であるためです。 元の要求メッセージのトランザクションがコミットされるまで、後続の要求メッセージは、メッセージング エンジンからアダプターに送信されません。
次のオブジェクト間の対話処理図に、受信メッセージのトランザクション送信時にアダプターとメッセージング エンジンが対話するようすを示します。 この例では、次の一連の対話が行われます。
アダプターが新しいバッチをエンジンから取得します。
アダプターが新しい MSDTC トランザクションを作成します。
アダプターが、トランザクションに参加しているデータ ソースの破壊的な読み取りを行います。
アダプターがメッセージを送信します。
アダプターはバッチで Done を呼び出し、MSDTC トランザクションとその BatchComplete コールバック ポインターを渡します。 エンジンは IBTDTCCommitConfirm インターフェイスを 返します。
エンジンはバッチを処理し、 その BatchComplete 実装でアダプターを呼び出し、そのメッセージ処理の状態をアダプターに伝達します。
バッチが成功した場合、アダプターはトランザクションをコミットし、コミットを示す値を使用
true
して IBTDTCCommitConfirm.DTCCommitConfirm API を呼び出します。
トランザクション送信元
トランザクション アダプターは、トランザクション以外のアダプターとほぼ同様です。 主な違いは、トランザクション アダプターの場合、メッセージ内のデータを、MSDTC トランザクションに参加しているリソースに送信する点です。
実装のヒント: トランザクション送信の場合、アダプターは、宛先にデータを書き込み、 IBTTransportBatch.DeleteMessage メソッド呼び出しを使用してデータを削除するために、同じ MSDTC トランザクションを使用する必要があります。 トランザクションが行われる必要があるのは、この 2 つの操作だけです。 IBTTransportBatch.Resubmit、IBTTransportBatch.MoveToNextTransport、IBTTransportBatch.MoveToSuspendQ などのその他の操作は、トランザクションする必要はありません。 これは、エンジンが暗黙的にトランザクションを使用し、これらの操作が送信先に対してアトミックである必要がないためです。
次のオブジェクト間の対話処理図に、アダプターとエンジンが対話するようすを示します。 イベントの順序は次のとおりです。
エンジンが新しいバッチをアダプターから取得します。
エンジンが 2 つのメッセージを新しいバッチに追加します。
エンジンはバッチで Done を呼び出し、アダプターはそのスレッド プールによって処理される内部送信キューにバッチをポストします。
アダプターが新しい MSDTC トランザクションを作成します。
アダプターがメッセージを送信し、MSDTC トランザクションに送信先を参加させます。 たとえば、SQL Server データベースへの書き込みなどです。
送信後に、アダプターが新しいバッチをエンジンから取得します。
アダプターは、正常に送信されたメッセージに対して DeleteMessage を呼び出します。
アダプターは、DTC トランザクションを渡すバッチで Done を呼び出します。 エンジンは IBTDTCCommitConfirm インターフェイスを 返します。
エンジンがバッチを処理し、メッセージをアプリケーション キューから削除します。
エンジンは、削除操作の成功に関する情報を使用して、アダプターの IBTBatchCallback インターフェイスを呼び出します。
バッチが成功した場合、アダプターがトランザクションをコミットします。
アダプターは IBTDTCCommitConfirm.DTCCommitConfirm を呼び出して、トランザクションが正常にコミットされたことをエンジンに通知します。
送信請求 - 応答のトランザクション アダプター
双方向受信とは異なり、双方向送信は同じ DTC トランザクションを使用して実行できます。 Transacted solicit-response アダプターでは、SubmitResponseMessage 操作と DeleteMessage 操作に同じ IBTTransportBatch を使用する必要があります。 このバッチは、送信請求 - 応答の組み合わせのメッセージの送受信時と同じ MSDTC トランザクションを使用します。 これにより、送信請求 - 応答のメッセージ交換における原子性が確保されます。
サービス コンポーネントと BYOT
メッセージング エンジン API は、MSDTC トランザクションの提供を必要とします。 ただし、一部の .NET コンポーネントはサービス コンポーネントとして使用されるよう設計されており、プログラムによるトランザクションのコミットや中止を許可しません。 この場合、トランザクションは、そのプラットフォームの COM+ ランタイムによって自動的にコミットされます。
このようなシナリオでは、アダプターで BYOT (Bring Your Own Transaction) を使用します。 こうすると、アダプターによる MSDTC トランザクションの作成と、このトランザクションを使用する .NET コンポーネントのインスタンス化が可能となります。このコンポーネントは作成されたトランザクションを継承するため、トランザクションを独自に作成することはありません。 .NET Frameworkは、この目的のために System.EnterpriseServices.BYOT を提供します。 SDK BaseAdapter は、この目的のために 、ヘルパー クラス BYOTTransaction を提供します。
競合状態の回避
トランザクション オブジェクトを作成し、それをBizTalk Serverに渡すアダプターを作成する場合は、次の処理を行うコードを記述する責任を負います。
バッチに関連付けられているメッセージ内のエラーを解決する。
バッチ操作に関連付けられているトランザクションの最終結果を決定する。
アダプターは、内部追跡データを維持するために、トランザクションの最終的な結果についてBizTalk Serverに通知する必要があります。 アダプターは、DTCConfirmCommit を呼び出して結果をBizTalk Serverに通知します。 アダプターがこれを行わないと、重大なメモリ リークが発生します。
上記の 2 つのタスク (エラーの解決と最終結果の決定) は単純に見えますが、実際には、これらのタスクは次に示す異なるスレッドの情報に基づいています。
アダプターは、アダプター内の BatchComplete コールバックにBizTalk Server渡された情報に基づいてエラーを処理します。 このコールバックはアダプターのスレッド上にあります。
DTCConfirmCommit は、 IBTDTCCommitConfirm オブジェクトのメソッドです。 IBTDTCCommitConfirm オブジェクトのインスタンスは、バッチ IBTTransportBatch::D one 呼び出しによって返されます。 このインスタンスは、アダプターのスレッドとは異なる IBTTransportBatch::D one 呼び出しと同じスレッド上にあります。
アダプターが IBTTransportBatch::D に対して行うすべての呼び出しに対して、バッチ送信の結果を報告するために、メッセージング エンジンによって別のスレッドで呼び出される対応するコールバック BatchComplete があります。 BatchComplete では、アダプターは、バッチが成功したか失敗したかに基づいてトランザクションをコミットまたはロールバックする必要があります。 どちらの場合も、アダプターは DTCConfirmCommit を呼び出して、トランザクションの状態をメッセージング エンジンに報告する必要があります。
アダプターの BatchComplete の実装では、IBTTransportBatch::D one によって返される IBTDTCCommitConfirm オブジェクトが BatchComplete の実行時に常に使用可能であると想定できるため、競合状態が発生する可能性があります。 ただし、IBTTransportBatch::D one が戻る前であっても、BatchComplete は別のメッセージング エンジン スレッドで呼び出すことができます。 アダプターが BatchComplete 実装の一部として IBTDTCCommitConfirm オブジェクトにアクセスしようとすると、アクセス違反が発生する可能性があります。
この問題は、次の例の イベントで解決されます。 この例では、イベントを使用するプロパティを通じてインターフェイス ポインターにアクセスします。 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 呼び出しでそれを使用します。