BPEL SOA Suite Essentials for WLI Users

トランザクションの処理

Kathryn Holden、Antony Reynolds、Tejas Joshi著

2008年9月公開

Oracle WLIユーザーのためのOracle SOA Suite基礎講座の第1回目では、Oracle WebLogic Integration(Oracle WLI)のトランザクション処理機能をOracle BPEL Process Managerの機能にマッピングする方法について説明します。

関連するダウンロード・リンク
 Oracle SOA Suite

はじめに

あ らゆるアプリケーションの設計において、トランザクションは常にその中心に位置しています。 コードを使用してトランザクションを制御できていた頃、その定義や管理は現在よりも容易でした。 選択肢は限られていたものの、開発者はできることとできないことについてきちんと把握していたのです。

こ の10年の間に、Java 2 Enterprise Edition(J2EE)やそのほかのテクノロジーが出現したことで、トランザクション処理をコンテナに委ねることが推奨されてきました。 しかし、コンテナ・ベースのサービスに対する理解が十分でない開発者にとっては、これが障壁となってしまいます。

トランザクション境界がコンテナ内に自動的に作成される場合、この問題はさらに悪化し、開発者は何が起きているのかほとんど理解できなくなります。

こ の記事は、WebLogic IntegrationおよびOracle BPEL Process Manager(Oracle BPEL PM)のコンテナ管理トランザクションとコンテナ定義トランザクションの未解明な点について取り上げることを目的としています。

一 般に、Oracle BPEL Process ManagerはグローバルXAトランザクション・グループをサポートしていないと誤解されています。 この原因として考えられるのは、Oracle WLIと異なり、"start transaction"や"stop transaction"というように、明確にラベルのついたアクティビティがOracle BPEL PMには含まれていないということです。 その代わりに、該当アクティビティの種類に応じて、トランザクション・グループの境界が暗黙的に指定されます。

まず、非常に単純なOracle WLIトランザクションを例にとって、これがどのようにOracle BPEL PMで実装されるかを確認してみます。 そのあとで、補正トランザクションなどの高度なトピックを取り上げます。

単純なトランザクション・プロセス

この例で取り上げるプロセスでは、3つのデータベースに対する更新とJMSメッセージのエンキューをおこないます。 すべてのリソースはXA対応であり、プロセスによりグローバル・トランザクションが形成されます。

Oracle WLIでのプロセスの実装

Oracle BPEL PMと同様に、Oracle WLIのビジネス・プロセスはトランザクション型です。 プロセスに含まれるステップはすべて、JTAトランザクションのコンテキスト内で実行されます。 トランザクションにより、1つまたは複数の処理が作業の原子単位として実行されます。 トランザクションに含まれる処理が1つでも失敗したら、すべての処理はロールバックされ、アプリケーションは以前の状態に戻ります。 ビジネス・プロセスのロジックがステートフルとして定義されているか、ステートレスとして定義されているかによって、ビジネス・プロセスのコンテキストに含まれるトランザクションは1つの場合と複数の場合があります。

ビジネス・プロセスが開始すると、このプロセスはコール元のトランザクションに参加するか、またはトランザク ションが存在しない場合は新規トランザクションを開始します。 暗黙的にも明示的にもトランザクション境界が存在しない場合、プロセスは1つのトランザクション内で実行されます。

最初の例では、ビジネス・プロセスにより4つの同期XAコールが起動します。 このプロセスは同期型のステートレスであり、 トランザクションはコンテナによって管理されます。

単純なOracle WLIトランザクション

暗黙的なトランザクション境界も明示的なトランザクション境界も定義されていないため、Oracle WLIは自動的にプロセス全体を1つのXAトランザクション内で実行します。 いずれかのデータソースに問題が発生し(データベースが停止している、またはJMSキューに接続できないなど)、例外ハンドラが定義されていない場合、ト ランザクション全体がロールバックされます。

Oracle WLIでビジネス・プロセスを構築する場合、プロセス内に配置されているブロッキング要素の場所に応じて、暗黙的トランザクションの境界が形成されます。 ビジネス・プロセスにノードが追加されると、ビジネス・プロセス内のトランザクション境界が変わります。

暗黙的トランザクションは、ビジネス・プロセスのロジックによって動作が自動的に決定される(または暗示的に示される)という理由と、プロセス設計において目に見えないという理由から、暗黙的と呼ばれています。

暗黙的トランザクションの境界は、プロセス内に配置されているブロッキング要素の場所に基づいて 形成されます。 これらの境界は、ビジネス・プロセスにプロセス・ノードが追加されると変わります。 また、ビジネス・プロセスはデフォルトでステートレスですが、トランザクション境界を変えるブロッキング要素を利用してステートフルに変更することもでき ます。

Oracle WLIでビジネス・プロセスのトランザクション動作を変えるノードは、次のとおりです。

  • すべての受信(ブロッキング)ノード(クライアント要求ノードまたはコントロール受信ノード)
  • パラレル・グループ・ノード
  • イベント選択ノード
  • それ自体がトランザクション境界を指定しないノードを(その境界内で)追加しても、既存のトランザクション境界に影響はありません。

次に、ビジネス・プロセスと暗黙的トランザクションの例を示します。 コントロール受信ノードはビジネス・プロセス内のブロッキング要素であるため、新規トランザクションが作成されます。

暗黙的トランザクション

ま た、Oracle WLIには、WLIパレットの中で"Transaction"ノードを使用することで、明示的にトランザクションを定義する機能があります。 この機能を使用すると、トランザクション境界内で特定のノードをグループ化して、暗黙的プロセス・トランザクションに影響を与えない局所的なロールバック にすることができます。 "Transaction"ノードを上記の単純な例に組み込むことで、1つのトランザクションではなく、2つの個別トランザクションとして実行できます。 次の図に、最初の2つのデータベース更新が1つのトランザクションに含まれており、JMSエンキューと3番目のデータベース更新が別のトランザクションに 含まれている様子を示します。

Oracle WLIの明示的トランザクション

WLIプロセス内に明示的にトランザクション・スコープを指定すると、Oracle WLIはオープン・トランザクション(ネスト化されていないトランザクション)を終了し、新たに別のトランザクションを開始します。 トランザクション・スコープが明示的に終了したあとでステップを追加すると、そのステップ用に新たな暗黙的XAトランザクションが開始します。 Oracle WLIでは、ネスト化されたトランザクションはサポートされていません。

WLIプロセスがステートレス・プロセス(同期または非同期)である場合、常に1つの暗黙的トランザクション内 で実行されます。 明示的トランザクションを、同期プロセスまたはステートレスな非同期プロセス内に定義することはできません。 したがって、上記の例に関していえば、ステートレス・プロセスにトランザクション・ノードを追加するだけで、このプロセスはステートフル・プロセスに変換 されます。

また、明示的トランザクションには次の制限事項があります。

  • 選択するノードは連続していなければなりません
  • 選択するノードには、クライアント要求ノードまたはコントロール受信ノードを含めることはできません
  • 選択するノードには、同期プロセスのクライアント要求ノードとクライアント応答ノードの間にあるノードを含めることはできません
  • パラレル・グループ・ノードまたはイベント選択グループ・ノードを明示的トランザクションに含めることで、トランザクションがブランチごとにネスト化する場合、これらのノードを選択ノードに含めることはできません
  • 選択するノードが既存の明示的トランザクションの内部にあってはなりません

Oracle WLIでのトランザクション処理について、詳しくは トランザクション境界に関するドキュメントを参照してください。

Oracle BPEL PMでのプロセスの実装

Oracle BPEL PMでは、Oracle WLI同様に、すべてのBPELプロセスが1つまたは複数のトランザクション・コンテキスト内で実行されます。 プロセスが実行を開始すると、トランザクションに関する次のいずれかの処理を実行します。

  1. このプロセスのために新しいトランザクションを開始する
  2. すでにオープンされているトランザクション内のプロセスを取得する

Oracle BPEL PMはこのトランザクションを使用してデータベース内のプロセス状態を更新し("デハイドレーション"と呼ばれる)、データベースに監査イベントを書き込 みます。 これらすべてが無効になっている場合も、トランザクション・コンテキスト内でプロセスを実行します。 Webサービス・インタフェースから起動された場合、使用できるトランザクション・コンテキストはないため、Oracle BPEL PMは1番のオプションを使用します。 トランザクション環境でJava APIから起動された場合、コール内で使用されたパラメータに応じて、いずれのオプションも使用できます。

Oracle BPEL PMは、できる限り多くのアクティビティを1つのトランザクションに含めようとします。 Oracle BPEL PMで、データベース内のプロセス状態の更新とトランザクションのコミットを実行させるアクティビティはわずかです。 すべてのアクティビティがトランザクションのコミットを発生させるわけではありません。 アクティビティに関連づけられたプロパティのために、プロセスが同じトランザクション・コンテキストを維持する場合もあります。

こ の単純なシナリオにおいて、デフォルトのトランザクション動作はOracle WLIと同様です。 プロセスがインスタンス化され、現在のトランザクション・コンテキストが存在しない場合、新しいトランザクションが作成されます。 Oracle WLIと同様に、Oracle BPEL PMでも、特定のアクティビティによりXAトランザクションの境界が指定されるため、トランザクションは終了を強いられます。 これらのアクティビティは、デハイドレーション・ストアにおけるBPELプロセスの状態を静止します。 この種類のアクティビティからプロセスが再開されると、新規トランザクションが開始します。 上記と同様のステップですが、次の図で1つの暗黙的トランザクションとしてOracle BPEL PMに実装した場合を示します。

単純なBPELトランザクション

2 番目のユースケースでは、トランザクションを2つの個別トランザクションに分割しますが、Oracle BPEL PMでは意図的に最初のトランザクションを終了させる必要があります。 これは次に示すとおり、Java Execアクティビティの内部で、"checkpoint"メソッドを明示的に使用することで実行できます。

<bpelx:exec name="checkpointJavaExec" language="java" version="1.4">
                          

     <![CDATA[
                          

     checkpoint();
                          

     ]]>
                          

</bpelx:exec>
                          

                        

"wait and receive"や、デハイドレーション(BPELプロセスの状態をデータベースに書き込み、トランザクションをコミットする)を発生させるそのほかのアクティビティに加えて、ターゲット・パートナー・リンクのidempotentプロパティをfalseに設定することで、起動したあとにトランザクションをコミットできます。 idempotentがfalseに設定されている場合、アクティビティの起動は実行後すぐにデハイドレートされ、デハイドレーション・ストアに記録されます。 これにより、最初のトランザクションが終了し、新しいトランザクションが開始します。 次の図に、どのように実装されるかを示します。

Oracle BPEL PMでは、アダプタであるESBや、同じBPELドメイン内のそのほかのプロセスをコールする際、同じトランザクション内にターゲットを含めるか、または別のトランザクションを開始するかを選択できます。 この動作は、パートナー・リンクのtransactionプロパティによって制御されます。 transactionプロパティの値にparticipateが設定されている場合、コール先は現在のトランザクションに追加されます。 transactionプロパティにそのほかの値が設定されている場合、コール先は別のトランザクションで実行されます。 これは、同じトランザクション内に複数のデータベース更新が含まれている場合に有効ですが、デメリットもあるので注意が必要です。

い ずれかのコール先プロセスによりトランザクションがロールバックされる場合、現在のBPELプロセス状態も前回コミットしたものにロールバックされます。 コミットが一度も実行されておらず、同期インタラクションからプロセスが起動されている場合、プロセスは完全に姿を消したように見えてしまいます。 この影響を最小限に抑えるに、トランザクションをロールバックするのではなく、データベース・アダプタがエラーをスローします - ただし、トランザクション整合性に影響がない場合のみです。(基本的には、データベース更新が 1回であればロールバックをせずに済みますが、 2 の更新があるとエラーによりロールバックが発生します)。

最後に注意すべき点として、フロー・アクティビティ(アクティビティのパラレル実行を指定するために使用)があ ります。Oracle BPEL PMでは、フロー・アクティビティは、スレッドを一時停止させるアクティビティの順番になるまで順次処理されます。 これは効率的ですが、サービス待機時間を短縮するために複数処理をパラレルで実行するという、フローの有用性が失われてしまいます。 このため、Oracle BPEL PMでは、 nonBlockingInvoke=trueと いうパートナー・リンク・プロパティが提供されており、同期サービスの起動を、内部的に非同期サービスの呼び出しとして扱うことができます。 内部的には、プロセスがJMSキューのメッセージを待機するので、結果としてトランザクションはここで終了します。 同時に、同期コールを実行して結果をキューに書き込むための新規スレッドが開始します。 これにより、フローに含まれる他の処理を並行して実行できます。

XAの枠を越えて:補正トランザクション

上記の例では、すべてのリソースがXAに準拠している場合の動作について説明しました。 XAに準拠していないアクティビティがある場合、補正トランザクションをプロセス内に構築する必要があります。 Oracle WLIとOracle BPEL PMのいずれにおいても、例外ハンドラを使用することでこれを実行するメカニズムが提供されています。

ま た、Oracle BPEL PMには起動可能な補正トランザクションの概念が含まれています。 これは例外ハンドラと似ており、スコープ・レベルで定義されますが、"Compensate"アクティビティによってのみ明示的に起動します。 補正は、トランザクションに参加できないシステムや、処理をトランザクションに含めるべきでないと決定されたシステムに対して、アプリケーションがこれら の処理を元に戻せるようにすることを目的としています。 たとえば、Webサービスにより在庫が減少されても、エラーによりプロセスをロールバックする必要が生じたとします。 この場合、補正ハンドラを定義して、在庫を増加させるWebサービスをコールすることで、事実上の逆行トランザクションを提供できます。 これにより、ロールバック・アクティビティを定義して、元に戻す必要のある処理を実行するコードを関連づけることができます。 これは、いくつかの例外を処理できるという点においても非常に便利であり、すべての作業を取り消す必要はありません。

スコープによって補正ハンドラが必要とされる場合、このサービスを非冪等としてマークするために、補正の必要な サービスの"idempotent"プロパティの値に"false"を設定する必要があります。 これにより、Oracle BPEL Process Managerは、非トランザクション型のリソースを起動したあとで新しいトランザクションを開始します。

次の図に、補正ハンドラの使用例と、明示的なフォワード・ベースの補正モデルを示します。 2番目のスコープの catchAllブロック内の明示的コールにより、 <compensate>が起動されていることを確認してください。

重要なポイントと推奨事項

Oracle WLIとOracle BPEL PMは、いずれもグローバルXAトランザクションを管理し、プロセスがインスタンス化された場合に暗黙的トランザクションを開始するツールを備えており、 トランザクションを強制終了させるよく似たアクティビティを含んでいます。 ただし、Oracle WLIとは違い、Oracle BPEL Process Managerでは、非同期のステートフル・プロセス内で複数トランザクションを実行できるだけでなく、同期プロセス内に定義することもできます。 また、補正を追加することで、非トランザクション型リソースにも補正トランザクションを提供する信頼性の高い標準メカニズムが提供されています。

BPELは、本質的にステートフルな言語です。 Oracle BPEL Process Managerでは、状態の管理にXAトランザクションが使用されており、アクティブなBPELプロセスの枠を越えてXAトランザクションを拡張できます。

何がコミットを発生させるのかに関するルールは単純です。BPELプロセスは、以下のアクティビティのあとでトランザクションをコミットし、新たなトランザクションを開始します。

  • receive - プロセス内での最初の受信で、プロセスが"transaction=participate"プロパティつきでコールされている場合(コール元プロセスの パートナー・リンクで指定されている)を除きます。このプロパティが指定されている場合、プロセスは既存のトランザクションに参加します。
  • checkpoint() - Java Execアクティビティ内のコール。
  • onMessage
  • wait - 非常に短い待機(最大でも2~3秒)の場合、Oracle BPEL PMはトランザクションをコミットしません。
  • onAlarm
  • invoke - パートナー・リンクが非冪等である("idempotent"パートナー・リンク・プロパティを使用)場合のみ。
  • End of process flow - プロセスがコール元のトランザクションに参加していない場合のみ(receiveの結果として)。

次の表に、各種アクティビティが実行された場合のトランザクション・ステータスをまとめます。

アクティビティ BPELプロセスの
トランザクション・ステータス
ターゲット・プロセスまたはアダプタの
トランザクション・ステータス
受信 新規トランザクション N/A
"transaction=participate"プロパティが指定された受信 コール元の既存トランザクションの使用 N/A
同期プロセスの起動 既存トランザクションの使用 新規トランザクション
"transaction=participate"パートナー・リンク・プロパティが指定された同期プロセスの起動 既存トランザクションの使用 既存BPELトランザクションの使用
"idempotent=false"パートナー・リンク・プロパティが指定された同期プロセスの起動 新規トランザクション 新規トランザクション
"nonBlockingInvoke=true"パートナー・リンク・プロパティが指定された同期プロセスの起動 新規トランザクション 新規トランザクション
非同期プロセスの起動 既存トランザクションの使用 新規トランザクション
"transaction=participate"パートナー・リンク・プロパティが指定された非同期プロセスの起動 既存トランザクションの使用 新規トランザクション
"idempotent=false"パートナー・リンク・プロパティが指定された同期プロセスの起動 新規トランザクション 新規トランザクション
数秒未満の待機 既存トランザクションの使用 N/A
数秒以上の待機 新規トランザクション N/A
checkpoint() 新規トランザクション N/A
フロー すべてのパラレル・アクティビティでの既存トランザクションの使用 N/A

Kathryn Kathryn Holdenは、SOAテクノロジーと統合テクノロジーを専門とするPrincipal Sales Consultantであり、オラクルに入社して3年になります。 オラクルに入社する前は、Integration SpecialistとしてBEAに6年間勤務していました。
Antony Antony Reynoldsは、 英国オラクルのMiddleware Solutions Directorであり、ビジネス要件をテクノロジー・ソリューションへと変換し、これらの要件をミドルウェア・スタック内で実現することに重点的に取り 組んでいます。 SOAとOracle Fusion Middlewareに関して人気の高い ブロガーでもあるAntonyは、オラクルに勤務して10年であり、さまざまな企業や職務におけるIT経歴は通算で20年以上になります。
Tejas Tejas Joshiは、 Oracle SOA ConsultingのSenior Architectであり、過去10年間にわたって、数々の統合ソリューションやSOAソリューションの設計に携わってきました。 2006年には"EMEA Technologist of the Year"賞を、また2007年には英国で知名度の高い企業での統合プロジェクトで優れた実績を収め、"Star Gold"賞を受賞しています。

Oracle WLIユーザーのためのOracle SOA Suite基礎講座シリーズでは、WebLogic Integrationの専門家とOracle SOA Suiteの専門家がペアになり、Oracle BPEL Process Managerにおける一般的なWLIパターンの実装について説明しています。 このシリーズのそのほかの記事も参照してください。