簡単な答えは、この問題を解決するには 2 つのオプションがあるということです。
- 並行状況で正しく動作するように、ストアド プロシージャを修正します。
- クラスター化された BizTalk ホスト内に SQL ポーリング受信ハンドラーを配置します。
以下は何が起こっているかの説明であり、その下に問題を修正するための実装の詳細を示します。
説明
これは、BizTalk の受信場所が複数のホスト インスタンスで実行されている場合 (つまり、受信場所で指定されたアダプターの受信ハンドラーが、複数のホスト インスタンスを持つホストで実行されている場合) に動作する方法によるものです。
この状況では、両方のホスト インスタンスが受信ハンドラーを実行します。
通常、これは問題ではありません。ほとんどの受信アダプターはこれを管理し、期待どおりの動作を提供します。たとえば、ファイル アダプタは、読み取り中のファイルをロックして、二重読み取りを防ぎます。
これが問題である主な場所は、まさにあなたが見ているものです - ポーリング SQL 受信場所がストアド プロシージャにヒットしている場合です。この場合、BizTalk には、正しい結果を得るために SQL プロシージャを信頼する以外に選択肢がありません。
手順を見ずに判断するのは難しいですが、レコードをクエリする方法は、一意の読み取りを保証していません.
おそらくあなたは次のようなものを持っています:
Select * From Record
Where Status = 'Unread'
Update Record
Set Status = 'Read'
Where Status = 'Unread'
上記の手順では、select と update の間に、select の別の呼び出しが侵入し、まだ更新されていないレコードを選択できるため、レコードが重複する可能性があります。
ソリューションの実装
手順の修正
この手順の簡単な修正方法の 1 つは、最初に一意の ID で更新することです。
Update Record
Set UpdateId = @@SPID, Status = 'Reading'
Where Status = 'Unread'
Select * From Record
Where UpdateId = @@SPID
And Status = 'Reading'
Update Record
Set Status = 'Read'
Where UpdateId = @@SPID
And Status = 'Reading'
@@SPID は一意である必要がありますが、そうでない場合は newid() を使用できます
クラスター化されたホストの使用
新しいホストを作成するときに、BizTalk サーバーの管理コンソール内で、そのホストがクラスター化されていることを指定できます。これについての詳細は、Kent Weare によるこの投稿にあります。
基本的に、各サーバーにホスト インスタンスを使用して通常どおりホストを作成し、ホストを右クリックしてクラスターを選択します。
次に、そのホストで機能するポーリング用の SQL 受信ハンドラーを作成し、このハンドラーを受信場所で使用します。
BizTalk クラスター化されたホストは、そのホストのメンバーであるすべてのアイテムが一度に 1 つのホスト インスタンスでのみ実行されることを保証します。これには SQL 受信場所が含まれるため、プロシージャを呼び出すときに競合状態が発生する可能性はありません。