8 XAでのアプリケーションの開発

マイクロサービス対応トランザクション・マネージャ(MicroTx)を使用してマイクロサービスのトランザクションを管理するには、既存のアプリケーション・コードにいくつか変更を加えて、MicroTxライブラリによって提供される機能を統合する必要があります。

MicroTxライブラリには、Java、Node.js、ORDS、Tuxedo、およびWebLogic Serverアプリケーション用があります。「サポートされている言語およびフレームワーク」を参照してください。
  1. 開始する前に、MicroTxをインストールし、アクセスできることを確認してください。
  2. マイクロサービスの実装にMicroTxクライアント・ライブラリを含めます。
  3. CDI注釈またはMicroTxクライアント・ライブラリAPIを使用して、必要なインターセプタとコールバックを登録します。
  4. 参加側マイクロサービスでCDI注釈またはMicroTxクライアント・ライブラリAPIを使用して、XA準拠のリソース・マネージャとの接続を取得します。
  5. MicroTxクライアント・ライブラリAPIを使用して、XAトランザクションが開始したことを示すトランザクション境界を区切ってから、トランザクションをコミットまたはロールバックします。

MicroTxを使用してXAトランザクションを管理するアプリケーションを開発するには、次のワークフローをガイドとして使用します。

タスク 説明 詳細
トランザクション参加側アプリケーションのリソース・マネージャを設定します XA準拠またはXA非準拠など、使用するリソース・マネージャのタイプを特定します。 リソース・マネージャの計画
MicroTxライブラリ・プロパティの構成情報を指定します。 すべてのトランザクション参加側アプリケーションおよびトランザクション・イニシエータ・アプリケーションに対してこのステップを実行し、アプリケーションがライブラリにアクセスできるようにします。 ライブラリ・プロパティの構成
MicroTxライブラリをアプリケーション・コードと統合します。 次の要因に基づいて、ライブラリを統合する適切な手順を選択します:
  • アプリケーションの開発フレームワーク
  • アプリケーションがトランザクションを開始するか、トランザクションに参加するか
アプリケーションに応じて、次のいずれかのタスクを実行します:
アプリケーションのデプロイ マイクロサービスの開発、テストおよびデプロイを個別に行います。アプリケーションでライブラリ・ファイルを使用してから、環境にアプリケーションをデプロイします。 アプリケーションのデプロイ

8.1 リソース・マネージャの計画

この項で説明する点を考慮して、リソース・マネージャについて計画します。選択するリソース・マネージャとその使用方法に応じて、アプリケーションの構成要件は異なります。

8.1.1 サポートされているリソース・マネージャ

トランザクション参加側サービスは、リソース・マネージャを使用してアプリケーション・データを格納できます。

XAトランザクションでは、MicroTxライブラリがリソース・マネージャのクライアント・ライブラリにアクセスする必要があります。

Java XAトランザクション参加側アプリケーションの場合、MicroTxライブラリは次のリソース・マネージャでテストされます:

  • Oracle Database 19c
  • PostgreSQL 14.2
  • MySQLおよびMicrosoft SQL Server

Node.js XAトランザクション参加側アプリケーションの場合、マイクロサービス対応トランザクション・マネージャ・ライブラリはOracle Database v19.xに対してテストされています。

XAトランザクション参加側アプリケーションは、XA非準拠リソース・マネージャ(MongoDB 4.1以降など)を使用できます。詳細は、「非XAリソースの最適化」を参照してください。

8.1.2 リソース・マネージャのサポートされているドライバ

使用するリソース・マネージャで機能する、正しいJDBCドライバとUCPバージョンを必要に応じて選択するのはアプリケーション開発者の責任です。

リソース・マネージャとしてのOracle Databaseの使用

Oracle Databaseで動作するJDBCドライバおよびUCPバージョンを使用する必要があります。MicroTxライブラリは、XAResourceオブジェクトにアクセスして、リソース・マネージャに対して様々なXA操作を実行します。XAResourceオブジェクトはJDBCドライバによって提供されます。

MicroTx Javaライブラリでは、パフォーマンスを向上させるために、ユニバーサル接続プール(UCP)がOracle JDBCドライバとともに使用されます。

Java用のMicroTxライブラリは、Oracle Databaseドライバのバージョン21.3.0.0でテストされています。

Oracle Databaseをリソース・マネージャおよびMicroTx Node.jsライブラリとして使用する場合は、参加側アプリケーションでnode-oracledb 5.3.0以上を使用する必要があります。

ロギング・ラスト・リソース(LLR)トランザクションを使用する場合、データベース・ドライバの追加要件はありません。

リソース・マネージャとしてのOracle Database以外の使用

XADataSourceおよびXAResourceインタフェースを実装する、サポートされているJDBCドライバを使用する必要があります。MicroTxライブラリは、XAResourceオブジェクトにアクセスして、リソース・マネージャに対して様々なXA操作を実行します。

8.1.3 非XAリソースの最適化

ロギング・ラスト・リソース(LLR)またはラスト・リソース・コミット(LRC)の最適化を使用すると、1つの非XAリソースがグローバル・トランザクションに参加できるようになります。

マイクロサービスには、いくつかの参加側アプリケーションが含まれることがあり、各アプリケーションが異なるリソース・マネージャに接続されている場合があります。たとえば、1つのマイクロサービスに、リソース・マネージャとしてOracle Databaseを使用するトランザクション・イニシエータ・アプリケーションと、リソース・マネージャとしてMongoDBを使用するトランザクション参加側アプリケーションが含まれるとします。MongoDBではXAプロトコルはサポートされません。しかしながら、MongoDBとOracle Databaseのどちらもグローバル・トランザクションに参加する必要があります。MicroTxでは、LLRまたはLRCの最適化を有効にすると、そのようなマイクロサービスに対してXAトランザクションプロトコルを使用できます。

ロギング・ラスト・リソース(LLR)の最適化について

LLRの最適化を使用すると、1つの非XAリソースがXAと同じACID保証を使用してグローバル・トランザクションに参加できるようになります。

XAリソースは、トランザクション・コーディネータによって送信されるXAリクエスト(準備、コミット、ロールバックなど)を処理できます。非ネイティブまたは非XAリソースは、このようなリクエストを処理できません。LLRおよびLRCの最適化によって、1つの非XAリソースがXAトランザクションに参加できるようになります。トランザクション・コーディネータは、トランザクションの他のすべてのブランチを準備してから、LLRまたはLRCブランチに対するローカル・トランザクション・コミットの実行を試みます。他のすべてのブランチが問題なく準備されていると仮定すると、ローカル・コミットの結果によってトランザクションの結果が決まります。ローカル・コミットが正常に行われると、トランザクションが正常にコミットされます。それ以外の場合はトランザクションがロールバックされます。

ローカル・コミットを実行する前に、トランザクション・コーディネータはLLRブランチにコミット・レコードを作成します。エラーが発生した場合、トランザクション・コーディネータは、LLRブランチでxa_recoverをコールしてトランザクションのリストをリカバリしようとします。LLRブランチがローカル・トランザクションを正常にコミットした場合、commitRecordによって、準備が完了した参加側のリストが返されます。LLRブランチがローカル・トランザクションのコミットに失敗した場合、recover()メソッドによって、参加側が記録されていないことを示す情報が返されます。

LLRブランチが、トランザクション・コーディネータのコミット・レコードも含むローカル・トランザクションのコミットに成功した場合、recover()によってコミット・レコードが返されます。

ラスト・リソース・コミット(LRC)の最適化について

MicroTxリリース22.3.2以降では、LRCの最適化を使用すると、1つの非XAリソースがXAと同じACID保証を使用せずにグローバル・トランザクションに参加できるようになります。

LRCでは、トランザクションのフローのシーケンスはLLRとほぼ同じです。イニシエータがトランザクション・コーディネータに対してcommitをコールすると、トランザクション・コーディネータはすべてのXAブランチを準備してから、LRCブランチでcommit()をコールします。唯一の違いは、エラーの場合に、commit()メソッドがNULLをLRCのcommitRecordの値として返すため、トランザクション詳細をリカバリできないことです。LLRでは、commit()メソッドによって、準備が完了した参加側のリストがレスポンスで返されます。LRCでcommit()がコールされると、ローカル・トランザクションがコミットされ、結果がトランザクション・コーディネータに返されます。ただし、準備が完了した参加側に関する情報は格納されていません。

トランザクション・ログの詳細情報が格納されないため、LRCの最適化は、サポートされているすべてのリソース・マネージャと連携します。ただし、ローカル・コミットが正常に完了したかどうかをトランザクション・コーディネータが確認する方法がないため、ヒューリスティックな結果になる可能性が高くなります。また、LRCではrecover()メソッドを使用できないため、エラーの場合にトランザクションをリカバリできません。

LLRまたはLRCの選択

エラーの場合に詳細をリカバリできるため、非XAリソースについてLLRの最適化を使用することを強くお薦めします。LRCの最適化を使用するのは、非XAリソースがcommitRecordの詳細すなわちトランザクション・ログの詳細を格納できない場合のみにしてください。

制限事項

  • MicroTxでは、LLRまたはLRCの最適化を使用すると、1つの非XAリソースを含む1つの参加側アプリケーションのみが、XAトランザクションに参加できます。マイクロサービスに複数の非XAリソースがある場合、MicroTxはこのマイクロサービスのXAトランザクション・プロトコルをサポートしません。たとえば、複数のLLR参加側またはLRC参加側を使用しようとすると、エラー・メッセージOnly one LLR or LRC participant is allowed to enlistが表示されます。

イニシエータ・アプリケーションがそのトランザクションを起動した後で参加する場合は、そのイニシエータ・アプリケーションでLLRまたはLRCリソースを使用できます。

8.1.4 複数のアプリケーションの共通リソース・マネージャ

MicroTxリリース22.3.1から、複数のトランザクション参加側サービスが単一のリソース・マネージャを使用し、トランザクションを最適化できます。

複数の参加側サービスに共通リソース・マネージャを使用する場合は、ORACLE_TMM_XA_RMID環境変数の値を指定してトランザクションを最適化できます。リソース・マネージャを共有するすべての参加側サービスに対して1つのブランチのみが作成されるため、トランザクションは最適化されます。

部門A、部門Bおよび部門Cは、リソース・マネージャを共有するが、異なるORACLE_TMM_XA_RMID値を持つ3つの参加側サービスであるとします。MicroTxは、部門ごとに新しいブランチを作成します。MicroTxで、トランザクションを追跡するためのブランチが合計3つ作成されます。

トランザクションを最適化するには、部門A、部門Bおよび部門CサービスのORACLE_TMM_XA_RMID環境変数に、ORCL1などの一意の値を指定します。

ORACLE_TMM_XA_RMID環境変数に値を指定すると、MicroTxは単一のリソース・マネージャを使用するすべてのサービスに対して単一のブランチを作成します。複数のブランチが作成されないため、トランザクションが最適化されます。このシナリオでは、MicroTxはトランザクションを最適化し、共通のリソース・マネージャと複数の参加側が関与するトランザクションを追跡する単一のブランチを作成します。この変数に値を指定しない場合、MicroTxはトランザクションを最適化せず、参加側サービスごとに1つずつ3つのブランチを作成します。

制限事項

  • 複数の参加側サービスで共有できるのは、XA準拠のリソース・マネージャのみです。非XAリソースを複数の参加側サービスと共有することはできません。
  • トランザクションに参加するイニシエータ・アプリケーションを含め、すべてのトランザクション参加側サービスに共通リソース・マネージャを使用できます。トランザクションを開始するがトランザクションに参加しないトランザクション・イニシエータ・サービスは、リソース・マネージャを必要としません。
  • リソース・マネージャごとに一意のRMIDを使用する必要があります。異なるリソース・マネージャに同じRMIDを使用すると、トランザクションは失敗します。

8.1.5 1つのアプリケーションでの複数のリソース・マネージャの構成

MicroTxリリース22.3.2以降では、1つの参加側サービスに対して複数のリソース・マネージャを使用できます。ビジネス・ロジックに基づいて、1つの参加側サービスは、複数のXA準拠リソース・マネージャに接続できます。ただし、1つのトランザクションで非XAリソースは1つしかサポートされません。

ノート:

この機能は、Javaアプリケーション用のMicroTxクライアント・ライブラリのみで提供されています。JPAまたはHibernateアプリケーションでは、XA準拠のリソース・マネージャのみがサポートされます。

8.1.6 XAトランザクションの動的リカバリについて

MicroTxリリース22.3.1から、トランザクション・コーディネータ・サーバーは、障害後にサーバーが再起動したときに進行中のトランザクションを再開します。

トランザクション・コーディネータが再起動するたびに、トランザクション・ストアで使用可能なデータに基づいて、すべてのプロトコル(XA、LRAおよびTCC)のトランザクションがリカバリされます。「トランザクション・リカバリについて」を参照してください。

また、XAトランザクション・プロトコルの場合、トランザクション・コーディネータは、コミットされていないトランザクションを動的にリカバリします。トランザクション・コーディネータは、コーディネータが失敗したときに進行中のトランザクションをチェックし、コミットまたはロールバック・コマンドを発行してトランザクションを完了します。トランザクションが見つからないか、すでに完了している場合、コーディネータはリソース・マネージャからトランザクション・レコードを削除します。

動的リカバリは、指定したリソース・マネージャID (RMID)に基づいて実行されます。各リソース・マネージャに指定するRMIDが一意であることを確認します。

トランザクション・コーディネータは、RMIDに基づいてリソース・マネージャごとに1回、動的リカバリを実行します。トランザクション・コーディネータ・インスタンスを再起動すると、リカバリ済情報は失われませんが、リカバリ済RMIDリストのマッピングは失われます。動的リカバリ中、RMIDごとにxa_recoverが1回コールされます。リソース・マネージャに関するリカバリ済情報はメモリーに保持されます。参加側が登録するたびに、トランザクション・コーディネータはRMIDを、メモリーに保持されているリカバリ済リソース・マネージャ・マッピングと照合します。これにより、リカバリ済リストにRMIDが存在しない場合にのみ、xa_recoverがコールされます。リカバリ済リストにRMIDが存在する場合、xa_recoverはコールされません。リソース・マネージャ・マッピングはメモリーに保持されるため、トランザクション・コーディネータが再起動すると、リカバリ済RMIDリストのリストが失われます。このようなシナリオでは、一意のRMIDが登録されるたびにリカバリが再度コールされます。

MicroTxがトランザクション・データを格納するようetcdまたはOracle Databaseを設定した場合は、コーディネータの再起動後、進行中のトランザクションに関する情報とトランザクションの詳細を取得できます。ただし、個別のトランザクション・ストアを設定しておらず、内部メモリーを使用してトランザクション詳細を格納している場合は、コーディネータがクラッシュまたは再起動すると、格納されているすべての情報が失われます。XAは動的リカバリをサポートしているため、内部メモリーを使用している場合、動的にリカバリされるすべての(xa_recover)XAトランザクションはロールバックされ、その後にxa_forgetが続きます。

8.2 リソース・マネージャとしてのPostgreSQLの構成

PostgreSQLをXAトランザクションのリソース・マネージャとして使用するには、準備完了状態のトランザクションおよびセッション・アフィニティを有効にする必要があります。

PostgreSQLをリソース・マネージャとして使用しない場合は、この項をスキップします。
デフォルトでは、max_prepared_transactionsの値は0に設定され、準備完了状態のトランザクションは無効になります。PostgreSQLで準備完了状態のトランザクションを有効にしないと、XAトランザクションを開始したときに次のエラー・メッセージが表示されます。
Exception: org.postgresql.util.PSQLException: ERROR: prepared transactions are disabled
  1. アプリケーションのpom.xmlファイルに次の依存関係を追加します。
    <dependency>
    	<groupId>org.postgresql</groupId>
    	<artifactId>postgresql</artifactId>
    	<version>RELEASE</version>
    </dependency>
  2. pgAdmin 4または他のPostgreSQLツールを使用してデータベースに接続し、次のSQL文を実行します。max_prepared_transactionsの値を正の数(100など)に設定して、PostgreSQLで準備完了状態のトランザクションを有効にします。
    SHOW max_prepared_transactions; 
    ALTER SYSTEM SET max_prepared_transactions = 100;
  3. PostgreSQLサービスを再起動します。
    services restart postgresql
  4. リソース・マネージャとしてPostgreSQLを使用するトランザクション参加側サービスのセッション・アフィニティまたはスティッキー・セッションを有効にします。セッション・アフィニティを有効にすると、一意のトランザクションまたはセッションに対するすべてのリクエストは、最初のリクエストを処理した参加側サービスの同じエンドポイントまたはレプリカにルーティングされます。「XA参加側のセッション・アフィニティの有効化」を参照してください。

8.3 トランザクション・タイムアウトの設定

XA参加側サービスから送信されたリクエストがアクティブである期間を指定します。トランザクションのコミットまたはロールバックが指定した期間内に行われないと、トランザクションはロールバックされます。

この値は、トランザクション・イニシエータ・アプリケーションのみに指定します。この値を参加側アプリケーションに指定しても無視されます。

参加側サービスから送信されるリクエストのトランザクション・タイムアウトを設定するには:

  1. MicroTxvalues.yamlファイルのtxMaxTimeoutパラメータに、トランザクションがアクティブなままである最大時間(ミリ秒)を指定します。デフォルト値は60000 msです。
    MicroTxvalues.yamlファイルは、installation_directory/otmm-RELEASE/otmm/helmchartsフォルダにあります。
  2. トランザクション・イニシエータ・サービスのtmm.propertiesファイル内のORACLE_TMM_TRANSACTION_TIMEOUTパラメータで、トランザクションをアクティブにしておく最長期間(ミリ秒)を指定します。トランザクションのコミットまたはロールバックが指定した期間内に行われないと、トランザクションはロールバックされます。デフォルト値(最小値)は60000です。
ORACLE_TMM_TRANSACTION_TIMEOUTの値はtxMaxTimeoutの値をオーバーライドできますが、txMaxTimeoutの値を超えることはできません。たとえば、txMaxTimeoutの値が70000で、ORACLE_TMM_TRANSACTION_TIMEOUTの値が80000の場合、最長タイムアウトは70000ミリ秒に設定されます。txMaxTimeoutの値が90000で、ORACLE_TMM_TRANSACTION_TIMEOUTの値が80000の場合、最長タイムアウトは80000ミリ秒に設定されます。

8.4 XAトランザクション通知の受信の登録

MicroTxリリース22.3.2以降では、トランザクション・イニシエータ・サービスおよび参加側サービスを登録して、通知を受信できます。MicroTxは、イベントの発生時(準備フェーズの前およびMicroTxがトランザクションを正常にコミットまたはロールバックしたとき)に、登録したサービスについて通知します。

MicroTxコーディネータが、登録したサービスについて通知します。イベントの発生時にビジネス・ロジックに基づいてサービスが追加のタスクを実行するようにする場合には、サービスの登録をお薦めします。登録するリソースごとに、コールバック・リソースを作成し、2つのメソッドを宣言する必要があります(MicroTxが、イベント発生時に通知を送信するためにこれらをコールします)。

ノート:

この機能は、Javaサービスでのみ使用可能です。
イベント通知を受信するために登録するトランザクション参加側サービスおよびイニシエータ・サービスに対して、次のタスクを実行します。
  1. アプリケーション・コード内に、コールバック・リソースを作成するコードを追加します(イベント発生時にMicroTxコーディネータがこれをコールします)。

    2つのメソッドを含むJAX-RSクラスを作成します。beforeCompletionメソッドおよびafterCompletionメソッドの宣言は必須です。これらのメソッド内に、アプリケーションのビジネス・ロジックに固有のコードを指定します。MicroTxコーディネータはbeforeCompletionメソッドをコールしてから、参加側に準備させるリクエストを送信します。afterCompletionメソッドは、トランザクションの完了後にイベントの最終ステータスを返します。ステータスは、STATUS_COMMITTEDまたはSTATUS_ROLLEDBACKです。

    次のサンプル・コードでは、EventListenerResourceがJAX-RSクラスの名前、transaction-syncはコールバック・リソースの名前です。クラスおよびコールバック・リソースには任意の名前を指定できます。後で指定する必要があるため、このリソースの名前を書き留めてください。

    サンプル・コード

    @Path("transaction-sync")
    public class EventListenerResource {
         
        /**
        * The MicroTx coordinator calls the beforeCompletion method before 
        * the two-phase transaction commit process starts. This call is executed with
        * the transaction  context of the transaction that is being committed.
        **/
        @POST
        @Path("/{gtrid}/beforecompletion")
        @Produces(MediaType.APPLICATION_JSON)
        public Response beforeCompletion(@PathParam("gtrid") String gtrid) {
            ...
            //tasks to be done before the transaction is completed 
            //enter the code based on your application's business logic
            return Response.status(Response.Status.OK).build();
        }
     
        /**
        * The MicroTx coordinator calls the afterCompletion method after the 
        * transaction is committed or rolled back.
        **/
        @POST
        @Path("/{gtrid}/aftercompletion/{status}")
        @Produces(MediaType.APPLICATION_JSON)
        public Response afterCompletion(@PathParam("gtrid") String gtrid, @PathParam("status") String status) {
           ...
           //tasks to be done after the transaction is completed 
           //enter the code based on your application's business logic
           return Response.status(Response.Status.OK).build();
        }
    }
  2. アプリケーションのビジネス・ロジックに基づいてイベント通知を受信するためにイニシエータ・サービスを登録します。

    次のサンプル・コードで、TrmRegisterSynchronization.register()メソッドをコールするのは、begin()をコールした後で、commit()またはrollback()をコールする前であることが示されます。TrmRegisterSynchronization.register()メソッドをコールする際には、前のステップで作成したコールバック・リソースの名前を渡す必要があります。

    サンプル・コード

    import oracle.tmm.jta.TrmUserTransaction;
    /**
    * Initiator method which initiates the transaction
    */
    transactionMethod() {
        TrmUserTransaction transaction = new TrmUserTransaction();
        transaction.begin();
        //
        TrmRegisterSynchronization.register(transaction.getTransactionID(), "/transaction-sync");
        ...
        // code that is specific to the application's business logic
        transaction.commit();
    }

    説明

    • transaction-syncは、前のステップで作成したコールバック・リソースの名前です。ご自身の環境に基づいてこの値を置き換えてください。
    • transaction.getTransactionID()は、現在のトランザクションのGTRIDです。TrmUserTransactionクラス・オブジェクトを使用して、現在のトランザクションのGTRIDを取得します。
  3. イベント通知を受信するために1つ以上のトランザクション参加側サービスを登録します。アプリケーションのビジネス・ロジックに基づいて、アプリケーションでイベント通知を受信する必要があるかどうかを決定できます。

    次のサンプル・コードは、GTRID値および以前に作成したコールバック・リソースの名前を明示的に渡して、TrmRegisterSynchronization.register()メソッドをコールする方法を示しています。

    サンプル・コード

    import oracle.tmm.jta.TrmRegisterSynchronization;
    /**
    * Participant method which is in transaction context.
    * Transaction event registration using GTRID
    */
    participantMethod1(){
        TrmXaContext trmXaContext = ThreadLocalXaContext.get();
        if (trmXaContext != null) {
            String currentTransactionGTRID = new String(trmXaContext.trmXid.getGlobalTransactionId());
            TrmRegisterSynchronization.register(currentTransactionGTRID, "/transaction-sync");
        }
        ...
        // code that is specific to the application's business logic
    }
     

    説明

    • transaction-syncは、前に作成したコールバック・リソースの名前です。ご自身の環境に基づいてこの値を置き換えてください。
    • currentTransactionGTRIDは、現在のトランザクションのGTRIDです。ThreadLocalから現在のトランザクションのGTRIDを取得するには、TrmXaContextを使用します。これは、トランザクション・イニシエータ・サービスにも参加側サービスにも適用されます。

8.5 ライブラリ・プロパティの構成

すべての参加側アプリケーションとイニシエータ・アプリケーションについてMicroTxライブラリ・プロパティの構成情報を指定します。

任意のコード・エディタでtmm.propertiesファイルを開き、次のパラメータの値を入力してMicroTxライブラリを構成します。
  • oracle.tmm.TcsUrl: MicroTxアプリケーションにアクセスするためのURLを入力します。「MicroTxへのアクセス」を参照してください。この値はトランザクション・イニシエータ・アプリケーションの場合に入力する必要があります。トランザクション参加側アプリケーションの場合、この値を指定する必要はありません。

  • oracle.tmm.TcsConnPoolSize: MicroTxライブラリへの接続数をMicroTxに入力します。デフォルト(最小)の接続数は10です。最大値は20です。この値は、サービスが実行する問合せ数に応じて変更できます。この値はイニシエータ・アプリケーションと参加側アプリケーションの両方に指定します。

  • oracle.tmm.CallbackUrl: 参加側サービスのURLを入力します。MicroTxは、指定されたURLを使用して参加側サービスに接続します。この値を次の形式で指定します。
    https://externalHostnameOfApp:externalPortOfApp/
    説明
    • externalHostnameOfApp: イニシエータ・サービスまたは参加側サービスの外部ホスト名。たとえば、bookTicket-appです。
    • externalPortOfApp: 参加側サービスにリモートでアクセスできるポート番号。たとえば、8081です。
    トランザクション参加側アプリケーションには、この値を指定する必要があります。トランザクション・イニシエータ・アプリケーションでは、この値を指定する必要はありません。
  • oracle.tmm.TransactionTimeout: トランザクションをアクティブにしておく最長期間(ミリ秒)を指定します。トランザクションのコミットまたはロールバックが指定した期間内に行われないと、トランザクションはロールバックされます。デフォルト(最小)値は60000です。この値はイニシエータ・アプリケーションと参加側アプリケーションの両方に指定します。

  • oracle.tmm.PropagateTraceHeaders: トランザクションを全面的にトレースする場合は、これをtrueに設定します。これにより、すべての受信リクエストおよび送信リクエストのトレース・ヘッダーが伝播されます。Helidonベースのマイクロサービスの場合、Helidonフレームワークがデフォルトでトレース・ヘッダーを伝播するため、トレース・ヘッダーを2回伝播しないように、このプロパティをfalseに設定します。このプロパティをtrueに設定できるのは、Helidon構成でトレース・ヘッダーの伝播が無効になっているときに、MicroTxを使用して分散トレースを有効にする場合です。その他のマイクロサービスの場合は、このプロパティをtrueに設定します。

  • oracle.tmm.xa.Rmid: MicroTxリリース22.3.1以降では、XAトランザクションで使用するリソース・マネージャごとに一意の文字列値を指定する必要があります。この値は、データ・ストアのプロパティとは関係ありません。RMIDとして指定する一意の値は、MicroTxがリソース・マネージャを識別するために使用されます。複数の参加側が同じリソース・マネージャを使用する場合、リソース・マネージャを共有する参加側に対して同じリソース・マネージャIDを指定します。
  • oracle.tmm.xa.XaSupport: XA準拠リソースを使用する場合は、これをtrueに設定します。これをfalseに設定するのは、非XAリソースを使用する単一のトランザクション参加側サービスに対してのみです。デフォルト値はtrueです。oracle.tmm.xa.XaSupporttrueに設定されると、oracle.tmm.xa.LLRSupportおよびoracle.tmm.xa.LRCSupportに設定された値は無視されます。
  • oracle.tmm.xa.LLRSupport: ロギング・ラスト・リソース(LLR)の最適化を有効にするには、これをtrueに設定します。この値は、非XAリソースをリソース・マネージャとして使用するトランザクション参加側サービスについてのみ設定します。デフォルト値はfalseです。oracle.tmm.xa.LLRSupporttrueに設定されると、oracle.tmm.xa.LRCSupportに設定された値は無視されます。
  • oracle.tmm.xa.LRCSupport: ラスト・リソース・コミット(LRC)の最適化を有効にするには、これをtrueに設定します。この値は、非XAリソースをリソース・マネージャとして使用するトランザクション参加側サービスについてのみ設定します。デフォルト値はfalseです。
たとえば、
oracle.tmm.TcsUrl = http://tmm-app:9000/api/v1
oracle.tmm.TcsConnPoolSize = 15
oracle.tmm.CallbackUrl = https://bookTicket-app:8081
oracle.tmm.PropagateTraceHeaders = true
oracle.tmm.TransactionTimeout = 60000
oracle.tmm.xa.XaSupport = true
oracle.tmm.xa.LLRSupport = false
oracle.tmm.xa.LRCSupport = false
oracle.tmm.xa.Rmid = ORCL1

アプリケーションとMicroTxが同じKubernetesクラスタ内にある場合はHTTPプロトコルを使用し、それ以外の場合はHTTPSプロトコルを使用します。

これらの構成値を環境変数として指定することもできます。application.propertiesファイルと環境変数の両方に値を指定した場合、環境変数に設定されている値がプロパティ・ファイルの値をオーバーライドすることに注意してください。

次の例は、環境変数を構成するためのサンプル値を示しています。

export ORACLE_TMM_TCS_URL= http://tmm-app:9000/api/v1
export ORACLE_TMM_CALLBACK_URL = http://bookTicket-app:8081
export ORACLE_TMM_PROPAGATE_TRACE_HEADERS = true
export ORACLE_TMM_TCS_CONN_POOL_SIZE = 15
export ORACLE_TMM_TRANSACTION_TIMEOUT = 60000
export ORACLE_TMM_XA_XASUPPORT = true
export ORACLE_TMM_XA_LLRSUPPORT = false
export ORACLE_TMM_XA_LRC_SUPPORT = false
export ORACLE_TMM_XA_RMID = ORCL1

環境変数名では大/小文字が区別されることに注意してください。

8.6 XAでのJavaアプリケーションの開発

JavaアプリケーションでMicroTxライブラリを使用します。

Java用のMicroTxライブラリは次の機能を実行します:

  • 参加側サービスをトランザクション内でトランザクション・コーディネータに登録します。
  • 使用する参加側アプリケーション・コードのために依存関係インジェクションを介してXADataSourceオブジェクトを注入し、関連付けられたXAResourceに対してstart()をコールします。参加側マイクロサービス(XAトランザクションのコンテキストでコールされるマイクロサービス)は、XA準拠のデータ・ソースを使用する必要があります。Javaでは、これはXADataSourceオブジェクトの使用を意味します。

    MicroTxライブラリは、構成済のデータ・ソースを参加側サービスに自動的に注入するため、アプリケーション開発者は@Injectまたは@Context注釈をアプリケーション・コードに追加する必要があります。アプリケーション・コードは、この関連付けを使用してDMLを実行します。

  • リソース・マネージャをコールして操作を実行します。

8.6.1 トランザクション・イニシエータとしてのJavaアプリケーションの構成

トランザクション・イニシエータ・サービスは、トランザクションを開始します。トランザクション・イニシエータ・サービスは、アプリケーションのビジネス・ロジックに基づいて、トランザクションの開始のみ、またはトランザクションの開始とトランザクションへの参加を行うことができます。

開始する前に、アプリケーションがトランザクションを開始するだけか、トランザクションを開始して参加するのかを確認します。2つのシナリオでは要件が若干異なるため、それに応じてアプリケーションを構成します。

2つのシナリオを検討して、アプリケーションがトランザクションを開始するだけか、トランザクションにも参加するかを理解します。
  • シナリオ1: 銀行振込アプリケーションによって、ある部門から別の部門に送金します。この場合、振込アプリケーションはトランザクションを開始するだけで、トランザクションには参加しません。振込アプリケーションは、トランザクションを完了するためにビジネス・ロジックに基づいて様々なサービスをコールします。データベース・インスタンスは、振込アプリケーションにアタッチされる場合とアタッチされない場合があります。
  • シナリオ2: 銀行振込アプリケーションによって、ある部門から別の部門に送金します。振込アプリケーションは、トランザクションごとに手数料として1%を請求します。この場合、振込アプリケーションはトランザクションを開始して参加します。データベース・インスタンスは、トランザクション情報を保存するために振込アプリケーションにアタッチされる必要があります。
Javaアプリケーションをトランザクション・イニシエータとして構成するには:
  1. MicroTxライブラリのプロパティ値を指定します。ライブラリ・プロパティの構成を参照してください。
  2. MicroTxライブラリをアプリケーションのpom.xmlファイルにmaven依存関係として含めます。次のサンプル・コードは22.3リリース用です。使用するリリースに基づいて、正しいバージョンを指定してください。
    <dependency>
         <groupId>com.oracle.tmm.jta</groupId>
         <artifactId>TmmLib</artifactId>
         <version>22.3</version>
    </dependency>
  3. oracle.tmm.jta.TrmUserTransactionパッケージをインポートします。
    import oracle.tmm.jta.TrmUserTransaction;
  4. すべての新しいトランザクションでTrmUserTransactionクラスのオブジェクトを初期化し、アプリケーション・コード内のトランザクション境界(トランザクションの開始、コミットまたはロールバックなど)を定めます。アプリケーション・ロジックがトランザクションを開始する前にオブジェクトを初期化します。
    次のコード・サンプルは、utというTrmUserTransactionクラスのインスタンスを作成する方法を示しています。
    UserTransaction ut = new oracle.tmm.jta.TrmUserTransaction();
  5. 次のコード・サンプルは、コールされた新しいXAトランザクションを開始する方法を示しています。
    • アプリケーションがトランザクションを開始するだけでトランザクションに参加しない場合は、次の行をアプリケーション・コードに追加して、XAトランザクションを開始します。

      
      ut.begin();
      ... // Implement the business logic to begin a transaction.
    • アプリケーションがトランザクションを開始して参加する場合は、次の行をアプリケーション・コードに追加して、XAトランザクションを開始します。

      
      ut.begin(true);
      ... // Implement the business logic to begin a transaction.
      
  6. RESTクライアントを作成します。

    次のコマンドによって、svcClientという新しいクライアントが作成されます。

    Client svcClient = ClientBuilder.newClient();

    このRESTクライアントを使用して、トランザクション参加側サービスのエンドポイントをコールし、トランザクションを実行します。トランザクション・イニシエータ・サービスはトランザクションを開始します。トランザクションを完了するために、イニシエータ・サービスは1つ以上の参加側サービスをコールする必要があります。参加側サービスをコールするときに、作成したRESTクライアントを使用します。

  7. ビジネス・ロジックに基づいて、トランザクションをコミットまたはロールバックします。
    • トランザクションをコミットするには:

      ut.commit();
    • トランザクションをロールバックするには:

      ut.rollback();
  8. Spring Bootアプリケーションの場合のみ、次のサンプル・コード・スニペットに示すように、準備、コミット、ロールバックのために、フィルタとXAResourceCallbacksを登録します。
    @Component
    public class Configuration extends ResourceConfig
    {
        public Configuration()
        {
            // Register the MicroTx XA resource callback which
            // coordinates with the transaction coordinator
            register(XAResourceCallbacks.class);
            // Register the filters for the MicroTx libraries that 
            // intercept the JAX_RS calls and manage the XA transactions
            register(TrmTransactionResponseFilter.class);
            register(TrmTransactionRequestFilter.class);
        }
    }
トランザクション・イニシエータ・サービスのサンプルXAアプリケーション・コードは、installation_directory\otmm-RELEASE\samples\xa\java\accountsにあります。これは、MicroTx JavaライブラリをJavaイニシエータ・アプリケーションのビジネス・ロジックとともに使用する方法の例です。このサンプル・アプリケーションは振込(Teller)という名前です。これは2つの部門間のトランザクションを開始します。部門Aをコールして一定金額を引き出し、部門Bをコールして預け入れます。
イニシエータ・サービスが、トランザクションを開始するだけでなくトランザクションに参加する場合、トランザクションに参加してリソース・マネージャと通信するアプリケーションのために追加の構成を行う必要があります。トランザクション参加側としてのJavaアプリケーションの構成を参照してください。

8.6.2 トランザクション参加側としてのJavaアプリケーションの構成

リソース・マネージャがXAに準拠しているかどうかに基づいて、環境変数を設定し、MicroTxライブラリの様々なクラスを実装して参加側アプリケーションを構成します。

8.6.2.1 XA準拠リソース・マネージャを使用するJDBCベースのJavaアプリケーションの構成

XA準拠のリソース・マネージャを使用する場合は、この項に記載されている情報を使用してJDBCベースのJava参加側アプリケーションを構成します。

  1. MicroTxクライアント・ライブラリのプロパティ値を指定します。

    次の例では、プロパティのサンプル値を指定しています。ご自身の環境に基づいて値を指定してください。

    oracle.tmm.TcsConnPoolSize = 15
    oracle.tmm.CallbackUrl = https://bookTicket-app:8081
    oracle.tmm.PropagateTraceHeaders = true
    oracle.tmm.TransactionTimeout = 60000
    oracle.tmm.xa.XaSupport = true

    oracle.tmm.xa.XaSupporttrueに設定されていることを確認します。

    各プロパティおよびその他のオプション・プロパティの詳細は、「ライブラリ・プロパティの構成」を参照してください。

  2. MicroTxライブラリをアプリケーションのpom.xmlファイルにmaven依存関係として含めます。次のサンプル・コードは22.3リリース用です。使用するリリースに基づいて、正しいバージョンを指定してください。
    <dependency>
         <groupId>com.oracle.tmm.jta</groupId>
         <artifactId>TmmLib</artifactId>
         <version>22.3</version>
    </dependency>
  3. XADatasourceオブジェクトを初期化します。

    MicroTxクライアント・ライブラリは、XADatasourceオブジェクトにアクセスする必要があります。このオブジェクトを使用してXAConnectionオブジェクトおよびXAResourceオブジェクトを作成し、リソース・マネージャまたはデータベース・サーバーに接続します。次のコードでは、接続オブジェクトを作成する際にアプリケーション・コードの先頭にXADatasourceオブジェクトをどのように定義するかを示しています。

    class oracle.tmm.jta.TrmConfig
    static void initXaDataSource(XADataSource xaDs)

    XADataSourceの詳細は、https://docs.oracle.com/javase/8/docs/api/javax/sql/XADataSource.htmlを参照してください。

  4. トランザクション参加側関数またはブロックで、MicroTxクライアント・ライブラリで使用されるXADatasourceオブジェクトを指定します。リソース・マネージャに接続するための資格証明およびその他の詳細を指定します。
    //Example for a participant using an Oracle Database:
    OracleXADataSource dataSource = new oracle.jdbc.xa.client.OracleXADataSource();
    dataSource.setURL(url); //database connection string
    dataSource.setUser(user); //username to access database
    dataSource.setPassword(password); //password to access database
    TrmConfig.initXaDataSource((XADataSource)dataSource);

    アプリケーション開発者は、XADataSourceを割り当てる際に、XA準拠JDBCドライバおよび必要なパラメータを設定する必要があります。

    MicroTxクライアント・ライブラリは、XADatasourceオブジェクトを使用してデータベース接続を作成します。

  5. トランザクション参加側の関数すなわちブロックで、XADatasourceオブジェクトを初期化した後に次のコード行を1回だけ追加します。
    oracle.tmm.jta.TrmConfig.initXaDataSource((XADataSource)xaDs);

    XADatasourceはJTAで定義されたインタフェースであり、JDBCドライバによって実装が提供されます。

    MicroTxクライアント・ライブラリは、このオブジェクトを使用してデータベースに接続し、XAトランザクションを開始し、準備、コミット、ロールバックなどの様々な操作を実行します。MicroTxライブラリは、依存関係インジェクションを使用してDMLを実行するためのSQL接続オブジェクトもアプリケーション・コードに提供します。

  6. 参加側サービスのコードに次の行を挿入して、アプリケーションがMicroTxクライアント・ライブラリによって渡された接続を使用するようにします。参加側アプリケーションの次のコードは、MicroTxクライアント・ライブラリによって作成されたconnectionオブジェクトを注入します。
    @Inject
    @TrmSQLConnection 
    private Connection connection;
  7. 参加側サービスのコードに次の行を挿入して、参加側サービスがDML操作を実行するたびに、注入されたconnectionオブジェクトを使用するようにします。
    Statement stmt1 = connection.createStatement();
    stmt1.execute(query);
    stmt1.close();

    ここで、connectionは、前のステップで注入したConnectionオブジェクトの名前です。

    これらのコード行は、参加側サービスが実行するDML操作ごとに挿入します。DML操作ごとにstmt1stmt2などの新しい文オブジェクトを作成しますが、MicroTxクライアント・ライブラリによって作成された同一のconnectionオブジェクトを使用します。

  8. Spring Bootに基づく参加側マイクロサービスの場合のみ、XAトランザクションに参加するリソース・エンドポイントを登録した後で次のタスクを実行します。
    1. 次のサンプル・コード・スニペットに示すように、準備、コミット、ロールバックのために、フィルタとXAResourceCallbacksを登録します。

      @Component
      public class JerseyConfig extends ResourceConfig
      {
          public JerseyConfig()
          {
              // Register the MicroTx XA resource callback which
              // coordinates with the transaction coordinator
              register(XAResourceCallbacks.class);
              // Register the filters for the MicroTx libraries that 
              // intercept the JAX_RS calls and manage the XA transactions
              register(TrmTransactionResponseFilter.class);
              register(TrmTransactionRequestFilter.class);
              
              // Bind the connection
              ...
          }
      }
    2. Spring Bootアプリケーションで1つのリソース・マネージャを使用している場合は、TrmXAConnectionFactoryオブジェクトをXAConnectionにバインドします。後で、TrmXAConnectionFactoryオブジェクト(MicroTx接続ファクトリ・オブジェクト)を使用します。これによってMicroTxが接続を処理します。

      @Component
      public class JerseyConfig extends ResourceConfig
      {
          public JerseyConfig()
          {
              // Register the filters as shown in the previous step
              ....
      
              register(new AbstractBinder() {
                  @Override
                  protected void configure() {
                  //Bind the TrmXAConnectionFactory object to an XAConnection object
                  bindFactory(TrmXAConnectionFactory.class).to(XAConnection.class);
                  }
              });
          }
      }
  9. 変更内容を保存します。
複数のJavaトランザクション参加側サービスがある場合は、すべての参加側サービスでこれらのステップを完了します。
8.6.2.2 複数のXA準拠リソース・マネージャを使用するJDBCベースのJavaアプリケーションの構成

複数のXA準拠のリソース・マネージャを使用する場合は、この項に記載されている情報を使用してJDBCベースのJava参加側アプリケーションを構成します。

アプリケーションは、複数のXA準拠リソース・マネージャに接続できます。また、アプリケーションは1つの非XAリソースに接続できます。
  1. MicroTxライブラリをアプリケーションのpom.xmlファイルにmaven依存関係として含めます。次のサンプル・コードは22.3リリース用です。使用するリリースに基づいて、正しいバージョンを指定してください。
    <dependency>
         <groupId>com.oracle.tmm.jta</groupId>
         <artifactId>TmmLib</artifactId>
         <version>22.3</version>
    </dependency>
  2. リソース・マネージャごとにDataSourceInfoオブジェクトを作成します。必ず、アプリケーションのYAMLファイルで指定したデータ・ソース名とリソース・マネージャIDを指定してください。

    サンプル・コマンド

    DataSourceInfo departmentDataSourceInfo = new DataSourceInfo("ORCL1-8976-9776-9873");
    departmentDataSourceInfo.setDataSourceName(departmentDataSource);
    
    DataSourceInfo creditDataSourceInfo = new DataSourceInfo("ORCL2-2134-5668-8672");
    creditDataSourceInfo.setDataSourceName(creditDataSource);

    説明

    • departmentDataSourceおよびcreditDataSourceは、アプリケーションのYAMLファイルで指定したXAデータ・ソースの名前です。
    • ORCL1-8976-9776-9873およびORCL2-2134-5668-8672は、アプリケーションのYAMLファイルでdepartmentDataSourceおよびcreditDataSourceにそれぞれ指定したリソース・マネージャIDです。

    後で、@Inject注釈を使用して、アプリケーションでこれらのデータ・ソースが使用されることを確認します。

  3. 作成したDataSourceInfoオブジェクトごとに、次のMicroTxクライアント・ライブラリ・プロパティの1つのみを入力します。次の例では、creditDataSourceオブジェクトのプロパティ値を指定します。同様に、他のリソース・マネージャのプロパティ値を指定できます。値を指定しない場合、リソースはデフォルトでXA準拠とみなされます。
    • XA準拠リソースの場合は、creditDataSource.setXaSupport();と入力します。
    • LLRの最適化を使用する非XAリソースの場合は、 creditDataSource.setLLRSupport();と入力します。
    • LRCの最適化を使用する非XAリソースの場合は、 creditDataSource.setLRCSupport();と入力します。
  4. XADatasourceオブジェクトを初期化します。アプリケーションで複数のリソース・マネージャを使用している場合は、XA準拠リソース・マネージャごとに次の方法でXADatasourceオブジェクトを初期化します。

    MicroTxクライアント・ライブラリは、XADatasourceオブジェクトにアクセスする必要があります。このオブジェクトを使用してXAConnectionオブジェクトおよびXAResourceオブジェクトを作成し、リソース・マネージャまたはデータベース・サーバーに接続します。次のコードでは、接続オブジェクトを作成する際にアプリケーション・コードの先頭にXADatasourceオブジェクトをどのように定義するかを示しています。

    class oracle.tmm.jta.TrmConfig
    static void initXaDataSource(XADataSource xaDS, DataSourceInfo creditDataSource)

    ここで、creditDataSourceは、以前に作成したDataSourceInfoオブジェクトです。

    すべてのリソース・マネージャについてこのステップを繰り返します。

    XADataSourceの詳細は、https://docs.oracle.com/javase/8/docs/api/javax/sql/XADataSource.htmlを参照してください。

  5. トランザクション参加側関数またはブロックで、MicroTxクライアント・ライブラリで使用されるXADatasourceオブジェクトを指定します。リソース・マネージャに接続するための資格証明およびその他の詳細を指定します。
    //Example for a participant using an Oracle Database:
    OracleXADataSource dataSource = new oracle.jdbc.xa.client.OracleXADataSource();
    dataSource.setURL(url); //database connection string
    dataSource.setUser(user); //username to access database
    dataSource.setPassword(password); //password to access database

    アプリケーション開発者は、XADataSourceを割り当てる際に、XA準拠JDBCドライバおよび必要なパラメータを設定する必要があります。

    MicroTxクライアント・ライブラリは、XADatasourceオブジェクトを使用してデータベース接続を作成します。

    すべてのリソース・マネージャについてこのステップを繰り返します。

  6. トランザクション参加側の関数すなわちブロックで、XADatasourceオブジェクトを初期化した後に次のコード行を1回だけ追加します。
    oracle.tmm.jta.TrmConfig.initXaDataSource(XADataSource xaDS, DataSourceInfo creditDataSource)

    ここで、 creditDataSourceは、以前に作成したDataSourceInfoオブジェクトです。

    MicroTxクライアント・ライブラリは、このオブジェクトを使用してデータベースに接続し、XAトランザクションを開始し、準備、コミット、ロールバックなどの様々な操作を実行します。MicroTxライブラリは、依存関係インジェクションを使用してDMLを実行するためのSQL接続オブジェクトもアプリケーション・コードに提供します。

    すべてのリソース・マネージャについてこのステップを繰り返します。

  7. Spring Bootに基づく参加側マイクロサービスの場合のみ、XAトランザクションに参加するリソース・エンドポイントを登録した後で次のタスクを実行します。
    1. 次のサンプル・コード・スニペットに示すように、準備、コミット、ロールバックのために、フィルタとXAResourceCallbacksを登録します。

      @Component
      public class JerseyConfig extends ResourceConfig
      {
          public JerseyConfig()
          {
              // Register the MicroTx XA resource callback which
              // coordinates with the transaction coordinator
              register(XAResourceCallbacks.class);
              // Register the filters for the MicroTx libraries that 
              // intercept the JAX_RS calls and manage the XA transactions
              register(TrmTransactionResponseFilter.class);
              register(TrmTransactionRequestFilter.class);
              
              // Bind the connection
              ...
          }
      }
    2. リソース・マネージャごとにBeanを初期化します。次のサンプル・コード・スニペットでは、2つのBean (アプリケーションが使用するリソース・マネージャごとに1つ)を初期化する方法を示しています。次のコード・サンプルで、departmentDataSourceおよびcreditDataSourceは、アプリケーションのYAMLファイルで指定したXAデータ・ソースの名前です。後で@Inject注釈を使用して参加側アプリケーションでこれらの接続が使用されることを確認するため、データ・ソースの名前を書き留めておきます。
      @Component
      public class JerseyConfig extends ResourceConfig
      {
          public JerseyConfig()
          {
              // Register the filters as shown in the previous step
              ....
          @Bean
          @TrmSQLConnection(name = "departmentDataSource")
          @Lazy
          @RequestScope
          public Connection departmentDSSqlConnectionBean(){
              return new TrmConnectionFactory().getConnection("departmentDataSource");
          }
      
          @Bean
          @TrmSQLConnection(name = "creditDataSource")
          @Lazy
          @RequestScope
          public Connection creditDSSqlConnectionBean(){
              return new TrmConnectionFactory().getConnection("creditDataSource");
          }
          }
      }
  8. 参加側サービスのコードに次の行を挿入して、アプリケーションがMicroTxクライアント・ライブラリによって渡された接続を使用するようにします。参加側アプリケーションの次のコードは、MicroTxクライアント・ライブラリによって作成されたconnectionオブジェクトを注入します。

    アプリケーションで複数のリソース・マネージャを使用している場合は、XA準拠リソース・マネージャごとに次の方法でconnectionオブジェクトを注入します。

    @Inject
    @TrmSQLConnection(name = "creditDataSource")
    private Connection creditConnection;

    ここで、creditDataSourceは、oracle.tmm.jta.common.DataSourceInfoパッケージのDataSourceInfoクラスのdataSourceName文字列に指定した値です。

    すべてのリソース・マネージャについてこのステップを繰り返します。

  9. 参加側サービスのコードに次の行を挿入して、参加側サービスがDML操作を実行するたびに、注入されたconnectionオブジェクトを使用するようにします。
    Statement stmt1 = creditConnection.createStatement();
    stmt1.execute(query);
    stmt1.close();

    ここで、creditConnectionは、前のステップで注入したConnectionオブジェクトの名前です。

    これらのコード行は、参加側サービスが実行するDML操作ごとに挿入します。DML操作ごとにstmt1stmt2などの新しい文オブジェクトを作成しますが、MicroTxクライアント・ライブラリによって作成された同一のcreditConnectionオブジェクトを使用します。

    すべてのリソース・マネージャについてこのステップを繰り返します。


  10. 変更内容を保存します。
複数のJavaトランザクション参加側サービスがある場合は、すべての参加側サービスでこれらのステップを完了します。
8.6.2.3 非XA JDBCリソースを使用するJavaアプリケーションの構成

XAをサポートしないJDBCリソースを使用する場合は、この項に記載されている情報を使用してJava参加側アプリケーションを構成します。

アプリケーションは、複数のXA準拠リソース・マネージャに接続できます。また、アプリケーションは1つの非XAリソースに接続できます。
  1. 1つのリソース・マネージャを使用する場合は、すべてのMicroTxクライアント・ライブラリ・プロパティの値を1つのファイル(tmm.propertiesファイルなど)に指定します。アプリケーションで複数のリソース・マネージャを使用している場合は、このステップをスキップします。

    oracle.tmm.xa.XaSupportfalseoracle.tmm.xa.LLRSupportまたはoracle.tmm.xa.LRCSupporttrueに設定されていることを確認します。

    • ロギング・ラスト・リソース(LLR)の最適化を有効にするには、環境変数に次の値を設定します。
      oracle.tmm.xa.XaSupport = false
      oracle.tmm.xa.LLRSupport = true
      oracle.tmm.xa.LRCSupport = false
      oracle.tmm.TcsConnPoolSize = 15
      oracle.tmm.CallbackUrl = https://bookHotel-app:8081
      oracle.tmm.PropagateTraceHeaders = true
      oracle.tmm.TransactionTimeout = 60000
    • ラスト・リソース・コミット(LRC)の最適化を有効にするには、環境変数に次の値を設定します。
      oracle.tmm.xa.XaSupport = false
      oracle.tmm.xa.LLRSupport = false
      oracle.tmm.xa.LRCSupport = true
      oracle.tmm.TcsConnPoolSize = 15
      oracle.tmm.CallbackUrl = https://bookHotel-app:8081
      oracle.tmm.PropagateTraceHeaders = true
      oracle.tmm.TransactionTimeout = 60000
  2. アプリケーションで複数のリソース・マネージャを使用している場合は、次のステップを実行して、MicroTxクライアント・ライブラリのプロパティ値を構成します。1つのリソース・マネージャを使用している場合は、このステップをスキップします。
    1. リソース・マネージャごとにDataSourceInfoオブジェクトを作成します。必ず、アプリケーションのYAMLファイルで指定したデータ・ソース名とリソース・マネージャIDを指定してください。

      サンプル・コマンド

      DataSourceInfo departmentDataSourceInfo = new DataSourceInfo("ORCL1-8976-9776-9873");
      departmentDataSourceInfo.setDataSourceName(departmentDataSource);
      
      DataSourceInfo creditDataSourceInfo = new DataSourceInfo("ORCL2-2134-5668-8672");
      creditDataSourceInfo.setDataSourceName(creditDataSource);

      説明

      • departmentDataSourceおよびcreditDataSourceは、アプリケーションのYAMLファイルで指定したXAデータ・ソースの名前です。
      • ORCL1-8976-9776-9873およびORCL2-2134-5668-8672は、アプリケーションのYAMLファイルでdepartmentDataSourceおよびcreditDataSourceにそれぞれ指定したリソース・マネージャIDです。

      後で、@Inject注釈を使用して、アプリケーションでこれらのデータ・ソースが使用されることを確認します。

    2. 作成したDataSourceInfoオブジェクトごとに、次のMicroTxクライアント・ライブラリ・プロパティの1つのみを入力します。次の例では、creditDataSourceオブジェクトのプロパティ値を指定します。同様に、他のリソース・マネージャのプロパティ値を指定できます。値を指定しない場合、リソースはデフォルトでXA準拠とみなされます。
      • XA準拠リソースの場合は、creditDataSource.setXaSupport();と入力します。
      • LLRの最適化を使用する非XAリソースの場合は、 creditDataSource.setLLRSupport();と入力します。
      • LRCの最適化を使用する非XAリソースの場合は、 creditDataSource.setLRCSupport();と入力します。
  3. MicroTxライブラリをアプリケーションのpom.xmlファイルにmaven依存関係として含めます。次のサンプル・コードは22.3リリース用です。使用するリリースに基づいて、正しいバージョンを指定してください。
    <dependency>
         <groupId>com.oracle.tmm.jta</groupId>
         <artifactId>TmmLib</artifactId>
         <version>22.3</version>
    </dependency>
  4. セッション・アフィニティを有効にします。「セッション・アフィニティの有効化」を参照してください。
  5. Datasourceオブジェクトを初期化します。

    MicroTxライブラリは、データ・ソース・オブジェクトにアクセスする必要があります。データ・ソース・オブジェクトを使用してjava.sql.Connectionオブジェクトを作成し、リソース・マネージャに接続します。次のコードは、データ・ソース・オブジェクトを定義する方法を示しています。

    このコードはアプリケーションの最初に指定する必要があります。したがって、initNonXaDataSourceメソッドは、サーバーの起動直後に、他のすべてのリクエストが処理される前にコールされます。

    • アプリケーションで1つのリソース・マネージャを使用している場合は、次のようにデータ・ソースを初期化します。

      class oracle.tmm.jta.TrmConfig
      static void initNonXaDataSource(DataSource NonXaDs)
    • アプリケーションで複数のリソース・マネージャを使用している場合は、非XA JDBCリソースに対して次の方法でデータ・ソース・オブジェクトを初期化します。参加側サービスは複数のXA準拠リソース・マネージャに接続できますが、1つのトランザクションでサポートされる非XAリソースは1つのみです。

      class oracle.tmm.jta.TrmConfig
      static void initNonXaDataSource(DataSource departmentDataSource, DataSourceInfo departmentDataSourceInfo)

      ここで、dataSourceInfoは、ステップ2で作成したオブジェクトです。

  6. トランザクション参加側関数またはブロックで、MicroTxライブラリで使用されるDataSourceオブジェクトを指定します。リソース・マネージャに接続するための資格証明およびデータベース・ドライバの詳細を指定します。次の例は、MySQLデータベースをLLRとして使用する場合に指定する必要がある詳細を示しています。同様に、他のデータベースの資格証明およびデータベース・ドライバ情報を指定できます。
    //Example for a participant using a MySQL database as resource manager
    this.dataSource = PoolDataSourceFactory.getPoolDataSource();
    this.dataSource.setURL(url); //Database connection string
    this.dataSource.setUser(user); //User name to access the database
    this.dataSource.setPassword(password); //Password to access the database
    //Database driver information for the MySQL database.
    //Provide the JDBC driver information that is specific to your database.
    this.dataSource.setConnectionFactoryClassName("com.mysql.cj.jdbc.MysqlDataSource");
    this.dataSource.setMaxPoolSize(15);

    アプリケーション開発者は、DataSourceを割り当てる際に、データベース固有のJDBCドライバおよび必要なパラメータを設定する必要があります。

    MicroTxライブラリは、DataSourceオブジェクトを使用してデータベース接続を作成します。

  7. トランザクション参加側の関数すなわちブロックで、Datasourceオブジェクトを初期化した後に次のコード行を1回だけ追加します。MicroTxライブラリは、このオブジェクトを使用してデータベース・トランザクションを開始します。MicroTxライブラリは、依存関係インジェクションを使用してDMLを実行するためのSQL接続オブジェクトもアプリケーション・コードに提供します。
    oracle.tmm.jta.TrmConfig.initNonXaDataSource((DataSource) NonXaDs);

    ここで、DatasourceはJTAで定義されたインタフェースであり、JDBCドライバによって実装が提供されます。

  8. 参加側サービスのコードに次の行を挿入して、アプリケーションがMicroTxライブラリによって渡された接続を使用するようにします。参加側アプリケーションの次のコードは、MicroTxライブラリによって作成されたconnectionオブジェクトを注入します。
    @Inject @TrmNonXASQLConnection private Connection connection;
  9. 参加側サービスにコードを挿入して、参加側サービスがDML操作を実行するたびに、注入されたconnectionオブジェクトを使用するようにします。ビジネス・シナリオに基づいて、注入されたconnectionオブジェクトを使用するコードを作成できます。次に、例のコード・スニペットを示します。
    Statement stmt1 = connection.createStatement();
    stmt1.execute(query);
    stmt1.close();

    これらのコード行は、参加側サービスが実行するDML操作ごとに挿入します。DML操作ごとにstmt1stmt2などの新しい文オブジェクトを作成しますが、MicroTxライブラリによって作成された同一のconnectionオブジェクトを使用します。

  10. Spring Bootに基づく参加側マイクロサービスの場合のみ、次のようにXAResourceコールバック(準備、コミット、ロールバックなど)と様々なフィルタを登録します:
    @Component
    public class JerseyConfig extends ResourceConfig
    {
        public JerseyConfig()
        {
            register(XAResourceCallbacks.class);
            register(TrmTransactionResponseFilter.class);
            register(TrmTransactionRequestFilter.class);
            register(new AbstractBinder() {
                @Override
                protected void configure() {
                bindFactory(TrmXAConnectionFactory.class).to(XAConnection.class);
                }
            });
        }
    }

    これは、XAトランザクションに参加するリソース・エンドポイントの登録に加えて行います。

  11. 変更内容を保存します。
8.6.2.4 非XAかつ非JDBCのリソースを使用するJavaアプリケーションの構成

XAもJDBCもサポートしないリソースを使用する場合は、この項に記載されている情報を使用してJava参加側アプリケーションを構成します。

アプリケーションは、複数のXA準拠リソース・マネージャに接続できます。ただし、トランザクションに参加できるのは1つの非XAリソースのみです。
  1. 開始する前に、MicroTxライブラリのプロパティ値を構成していることを確認してください。ライブラリ・プロパティの構成を参照してください。
    oracle.tmm.xa.XaSupportfalseoracle.tmm.xa.LLRSupportまたはoracle.tmm.xa.LRCSupporttrueに設定されていることを確認します。
    • ロギング・ラスト・リソース(LLR)の最適化を有効にするには、環境変数に次の値を設定します。
      oracle.tmm.xa.XaSupport = false
      oracle.tmm.xa.LLRSupport = true
      oracle.tmm.xa.LRCSupport = false
    • ラスト・リソース・コミット(LRC)の最適化を有効にするには、環境変数に次の値を設定します。
      oracle.tmm.xa.XaSupport = false
      oracle.tmm.xa.LLRSupport = false
      oracle.tmm.xa.LRCSupport = true
  2. MicroTxライブラリをアプリケーションのpom.xmlファイルにmaven依存関係として含めます。次のサンプル・コードは22.3リリース用です。使用するリリースに基づいて、正しいバージョンを指定してください。
    <dependency>
         <groupId>com.oracle.tmm.jta</groupId>
         <artifactId>TmmLib</artifactId>
         <version>22.3</version>
    </dependency>
  3. セッション・アフィニティを有効にします。「セッション・アフィニティの有効化」を参照してください。
  4. NonXAResourceインタフェースを実装します。
    public class MongoDbNonXAResource implements NonXAResource {
    // Provide application-specific code for all the methods in the NonXAResource interface.
    }

    NonXAResourceインタフェースの詳細は、Transaction Manager for Microservices Java APIリファレンスを参照してください。

    LRCの最適化を有効にした場合、recover()メソッドをNonXAResourceインタフェースに実装する必要はありません。LRCでは、commit()メソッドがcommitRecordNULLを返すためです。

  5. NonXAResourceインタフェースを実装した後、MicroTxライブラリ・ファイルをインポートし、非XAリソースを生成します。作成した非XAリソースに@NonXa注釈を付けます。MicroTxライブラリは、注釈を付けたオブジェクトを消費します。

    次の例は、MongoDBリソースの実装例を示しています。業務要件に基づいてアプリケーションのコードを作成します。この例で、NonXaResourceFactoryクラスがNonXAResourceを提供します。非XAリソースを生成し、MicroTxライブラリが非XAリソースを消費します。

    package com.oracle.mtm.sample.nonxa;
    
    import oracle.tmm.jta.nonxa.NonXAResource;
    import oracle.tmm.jta.nonxa.NonXa;
    
    import javax.enterprise.inject.Produces;
    import javax.inject.Inject;
    import javax.ws.rs.ext.Provider;
    import java.util.function.Supplier;
    
    @Provider
    public class NonXaResourceFactory implements Supplier<NonXAResource> {
    
        @Inject
        MongoDbNonXAResource nonXAResource;
    
        @Produces    
        @NonXa
        public NonXAResource getNonXAResource() {
            return nonXAResource;
        }
    
      @Override
        public NonXAResource get() {
            return getNonXAResource();
        }
    }
  6. 変更内容を保存します。

8.6.3 トランザクション参加側としてのJPAベースのJavaアプリケーションの構成

この項に記載されている情報を使用して、HibernateまたはEclipseLinkを、HelidonまたはSpring BootアプリケーションのJPAプロバイダとして構成します。

トランザクション参加側としてのJPAベースのアプリケーションの構成は、トランザクション参加側としてのJDBCベースのJavaアプリケーションの構成に似ています。

JDBCベースのJavaアプリケーションをトランザクション参加側として構成するには、カスタム・データ・ソース・オブジェクトを作成し、このオブジェクトをMicroTxライブラリに渡します。Javaアプリケーション・コードで、カスタム・データ・ソースの詳細をTrmSQLConnection接続オブジェクトに注入してから、注入されたオブジェクトを使用するようにアプリケーション・コードを更新します。

JPAベースのJavaアプリケーションをトランザクション参加側として構成するには、カスタム・データ・ソース・オブジェクトを作成し、このオブジェクトをMicroTxライブラリに渡します。アプリケーション・コードで、カスタム・データ・ソースの詳細をTrmEntityManagerオブジェクトに注入してから、注入されたオブジェクトを使用するようにアプリケーション・コードを更新します。

8.6.3.1 XA準拠リソース・マネージャを使用するJPAベースのJavaアプリケーションの構成

XA準拠のリソース・マネージャを使用する場合は、この項に記載されている情報を使用して、XAトランザクションに参加するHelidonまたはSpring BootアプリケーションのJPAプロバイダとしてHibernateまたはEclipseLinkを使用します。

アプリケーションは、複数のXA準拠リソース・マネージャに接続できます。アプリケーションで複数のXA準拠リソース・マネージャを使用している場合は、リソース・マネージャごとに次のステップを実行します。
  1. MicroTxクライアント・ライブラリ・プロパティのプロパティ値を指定します。

    次の例では、プロパティのサンプル値を指定しています。ご自身の環境に基づいて値を指定してください。

    oracle.tmm.TcsConnPoolSize = 15
    oracle.tmm.CallbackUrl = https://bookTicket-app:8081
    oracle.tmm.PropagateTraceHeaders = true
    oracle.tmm.TransactionTimeout = 60000
    oracle.tmm.xa.XaSupport = true

    oracle.tmm.xa.XaSupporttrueに設定されていることを確認します。

    各プロパティおよびその他のオプション・プロパティの詳細は、「ライブラリ・プロパティの構成」を参照してください。

  2. MicroTxライブラリをアプリケーションのpom.xmlファイルにmaven依存関係として含めます。次のサンプル・コードは22.3リリース用です。使用するリリースに基づいて、正しいバージョンを指定してください。
    <dependency>
         <groupId>com.oracle.tmm.jta</groupId>
         <artifactId>TmmLib</artifactId>
         <version>22.3</version>
    </dependency>
  3. アプリケーション・コードを含むフォルダに.javaファイルを作成して、XADataSourceConfigオブジェクトを初期化します。XADataSourceConfigクラスには、カスタム・データ・ソース・オブジェクトおよびエンティティ・マネージャ・ファクトリ・オブジェクトを作成するメソッドが含まれています。

    次のコード例は、XADataSourceConfigクラス内のライブラリを初期化し、departmentDataSourceというカスタム・データ・ソースを作成し、emfというエンティティ・マネージャ・ファクトリ・オブジェクトを作成する方法を示しています。ご自身のアプリケーション用に同様のコードを作成できます。

    カスタム・データ・ソース・オブジェクトには、リソース・マネージャに接続するための詳細が含まれています。アプリケーション開発者は、カスタム・データ・ソース・オブジェクトを作成する際に、XA準拠JDBCドライバおよび必要なパラメータを設定する必要があります。

    package com.oracle.mtm.sample;
    
    import oracle.tmm.common.TrmConfig;
    import oracle.tmm.jta.jpa.hibernate.HibernateXADataSourceConnectionProvider;
    import oracle.ucp.jdbc.PoolDataSourceFactory;
    import oracle.ucp.jdbc.PoolXADataSource;
    import org.hibernate.jpa.HibernatePersistenceProvider;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.persistence.EntityManagerFactory;
    import javax.sql.DataSource;
    import java.sql.SQLException;
    import java.util.Properties;
    
    @Configuration
    @EnableTransactionManagement
    public class XADataSourceConfig {
        @Value("${spring.xads.datasource.url}")
        private String url;
        @Value("${spring.xads.datasource.username}")
        private String username;
        @Value("${spring.xads.datasource.password}")
        private String password;
        @Value("${spring.xads.datasource.oracleucp.min-pool-size}")
        private String minPoolSize;
        @Value("${spring.xads.datasource.oracleucp.initial-pool-size:10}")
        private String initialPoolSize;
    
        @Value("${spring.xads.datasource.oracleucp.max-pool-size}")
        private String maxPoolSize;
    
        @Value("${spring.xads.datasource.oracleucp.data-source-name}")
        private String dataSourceName;
    
        @Value("${spring.xads.datasource.oracleucp.connection-pool-name}")
        private String connectionPoolName;
    
        @Value("${spring.xads.datasource.oracleucp.connection-factory-class-name:oracle.jdbc.xa.client.OracleXADataSource}")
        private String connectionFactoryClassName;
        
        //Create a custom data source object. Provide credentials and other details to connect to the resource manager.
        @Bean(name = "departmentDataSource")
        @Primary
        public DataSource getDataSource() {
            DataSource pds = null;
            try {
                pds = PoolDataSourceFactory.getPoolXADataSource();
    
                ((PoolXADataSource) pds).setConnectionFactoryClassName(connectionFactoryClassName);
                ((PoolXADataSource) pds).setURL(url);
                ((PoolXADataSource) pds).setUser(username);
                ((PoolXADataSource) pds).setPassword(password);
                ((PoolXADataSource) pds).setMinPoolSize(Integer.valueOf(minPoolSize));
                ((PoolXADataSource) pds).setInitialPoolSize(10);
                ((PoolXADataSource) pds).setMaxPoolSize(Integer.valueOf(maxPoolSize));
    
                ((PoolXADataSource) pds).setDataSourceName(dataSourceName);
                ((PoolXADataSource) pds).setConnectionPoolName(connectionPoolName);
    
                System.out.println("XADataSourceConfig: XADataSource created");
            } catch (SQLException ex) {
                System.err.println("Error connecting to the database: " + ex.getMessage());
            }
            return pds;
        }
    
        // Create an entity manager factory object
        @Bean(name = "entityManagerFactory")
        public EntityManagerFactory createEntityManagerFactory() throws SQLException {
            LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
    
            entityManagerFactoryBean.setDataSource(getDataSource());
            entityManagerFactoryBean.setPackagesToScan(new String[] { "com.oracle.mtm.sample.entity" });
            entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    
            entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
            entityManagerFactoryBean.setPersistenceUnitName("mydeptxads");
            Properties properties = new Properties();
            properties.setProperty( "javax.persistence.transactionType", "RESOURCE_LOCAL"); // change this to resource_local
            properties.put("hibernate.show_sql", "true");
            properties.put("hibernate.dialect", "org.hibernate.dialect.Oracle12cDialect");
            properties.put("hibernate.format_sql", "true");
            properties.put("hbm2ddl.auto", "validate");
            properties.put("hibernate.connection.provider_class", "oracle.tmm.jta.jpa.hibernate.HibernateXADataSourceConnectionProvider");
            entityManagerFactoryBean.setJpaProperties(properties);
            entityManagerFactoryBean.afterPropertiesSet();
            EntityManagerFactory emf = (EntityManagerFactory) entityManagerFactoryBean.getObject();
            System.out.println("entityManagerFactory = " + emf);
            // Pass the entity manager factory object to the MicroTx Library
    
            // If you are using a single resource manager with your application, 
            //pass the entity manager factory object to the MicroTx library in the following way.
            TrmConfig.initEntityManagerFactory(emf);
            // If you are using multiple resource managers with your application,
            // pass the entity manager factory object to the MicroTx library in the following way. 
            TrmConfig.initEntityManagerFactory(emf, departmentDataSource, ORCL1-8976-9776-9873);
    
            return emf;
        }
    }

    エンティティ・マネージャ・ファクトリ・オブジェクトを初期化するには、アプリケーションが1つのリソース・マネージャまたは複数のリソース・マネージャに接続するかに応じて、必要なパラメータをTrmConfig.initEntityManagerFactory()に渡します。

    • アプリケーションが1つのリソース・マネージャに接続する場合は、エンティティ・マネージャ・ファクトリ・オブジェクトを作成し、それをMicroTxライブラリに渡します。次のサンプル・コードで、emfはエンティティ・マネージャ・ファクトリ・オブジェクトの名前です。

      TrmConfig.initEntityManagerFactory(emf);
    • アプリケーションが複数のリソース・マネージャに接続する場合は、TrmConfig.initEntityManagerFactory()をコールするときに次のパラメータを渡す必要があります。

      TrmConfig.initEntityManagerFactory(emf, departmentDataSource, ORCL1-8976-9776-9873);

      説明

      • emfは、作成したエンティティ・マネージャ・ファクトリ・オブジェクトです。これをMicroTxライブラリに渡します。
      • departmentDataSourceは、前述のサンプル・コードでTrmConfig.initEntityManagerFactory()をコールする前に作成したデータ・ソースの名前です。
      • ORCL1-8976-9776-9873は、リソース・マネージャID (RMID)です。
  4. Spring Bootアプリケーションの場合のみ、XAトランザクションに参加するリソース・エンドポイントを登録した後で次のタスクを実行します。
    1. 次のサンプル・コード・スニペットに示すように、準備、コミット、ロールバックのために、フィルタとXAResourceCallbacksを登録します。

      @Component
      public class Configuration extends ResourceConfig
      {
          public Configuration()
          {
              // Register the MicroTx XA resource callback which
              // coordinates with the transaction coordinator
              register(XAResourceCallbacks.class);
              // Register the filters for the MicroTx libraries that 
              // intercept the JAX_RS calls and manage the XA transactions
              register(TrmTransactionResponseFilter.class);
              register(TrmTransactionRequestFilter.class);
              
              // Bind the connection
              ...
          }
      }
    2. 複数のリソース・マネージャを使用している場合は、このステップをスキップします。Spring Bootアプリケーションで1つのリソース・マネージャを使用している場合は、TrmEntityManagerオブジェクトをEntityManagerにバインドします。後で、TrmEntityManager オブジェクトをアプリケーション・コードで使用します。これによってMicroTxが接続を処理します。

      @Component
      public class Configuration extends ResourceConfig
      {
          public Configuration()
          {
              // Register the filters as shown in the previous step
              ....
              // Bind the connection
              register(new AbstractBinder() {
                  @Override
                  protected void configure() {
                      //Bind the TrmEntityManager object to an EntityManager object
                      bindFactory(TrmEntityManagerFactory.class).to(EntityManager.class);
                  }
              });
          }
      }
    3. 1つのリソース・マネージャを使用している場合は、このステップをスキップします。複数のリソース・マネージャを使用している場合は、リソース・マネージャごとにBeanを初期化します。次のサンプル・コード・スニペットでは、2つのBean (アプリケーションが使用するリソース・マネージャごとに1つ)を初期化する方法を示しています。次のコード・サンプルで、departmentDataSourceおよびcreditDataSourceは、アプリケーションのYAMLファイルで指定したXAデータ・ソースの名前です。後で@Inject注釈を使用して参加側アプリケーションでこれらの接続が使用されることを確認するため、データ・ソースの名前を書き留めておきます。
      @Component
      public class Configuration extends ResourceConfig
      {
          public Configuration()
          {
              // Register the filters as shown in the previous step
              ....
          // Initialize a bean for every resource manager that you want to use with your app
          @Bean
          @TrmEntityManager(name = "departmentDataSource")
          @Lazy
          @RequestScope
          public EntityManager departmentDSSqlConnectionBean() throws SQLException {
              return new TrmEntityManagerFactory().getEntityManagerByName("departmentDataSource");
          }
      
          @Bean
          @TrmEntityManager(name = "creditDataSource")
          @Lazy
          @RequestScope
          public EntityManager creditDSSqlConnectionBean() throws SQLException {
              return new TrmConnectionFactory().getConnection("creditDataSource");
          }
          }
      }
  5. 参加側サービスのコードに次の行を挿入して、アプリケーションがMicroTxクライアント・ライブラリによって渡された接続を使用するようにします。参加側アプリケーションの次のコードは、MicroTxクライアント・ライブラリによって作成されたconnectionオブジェクトを注入します。
    • 1つのアプリケーションで1つのリソース・マネージャを使用する場合は、次のコード・サンプルに示すようにEntityManagerオブジェクトを注入します。

      @Inject
      @TrmEntityManager 
      private EntityManager emf;
    • アプリケーションで複数のリソース・マネージャを使用する場合は、次のコード・サンプルに示すようにリソース・マネージャごとにEntityManagerオブジェクトを注入します。

      @Inject
      @TrmEntityManager(name = "departmentDataSource")
      private EntityManager emf;
      
      @Inject
      @TrmEntityManager(name = "creditDataSource")
      private EntityManager emf;

      ここで、emfはエンティティ・マネージャ・ファクトリ・オブジェクト、departmentDataSourceおよびcreditDataSourceは前のステップで作成したデータ・ソース・オブジェクトです。前のコード・サンプルは、departmentDataSourceの詳細を示しています。同様の方法で、creditDataSourceなどの他のリソース・マネージャの情報を指定します。

  6. アプリケーション・コードで、MicroTxライブラリに渡したエンティティ・マネージャ・オブジェクトを注入します。ビジネス・ロジックに基づいてアプリケーション・コード内でエンティティ・マネージャ・オブジェクトを使用し、このオブジェクトを使用してデータベースに接続します。

    次のコード例は、エンティティ・マネージャ・オブジェクトの注入および使用の方法を示しています

    @POST
        @Path("{accountId}/withdraw")
        public Response withdraw(@PathParam("accountId") String accountId, @QueryParam("amount") double amount, @Context EntityManager entityManager) {
        // Application code or business logic
            if(amount == 0){
                return Response.status(422,"Amount must be greater than zero").build();
            }
            try {
                if (this.accountService.getBalance(accountId, entityManager) < amount) {
                    return Response.status(422, "Insufficient balance in the account").build();
                }
                if(this.accountService.withdraw(accountId, amount, entityManager)) {
                    config.getLogger().log(Level.INFO, amount + " withdrawn from account: " + accountId);
                    return Response.ok("Amount withdrawn from the account").build();
                }
            } catch (SQLException | IllegalArgumentException e) {
                config.getLogger().log(Level.SEVERE, e.getLocalizedMessage());
                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
            }
            return Response.serverError().entity("Withdraw failed").build();
        }
  7. 変更内容を保存します。
複数のトランザクション参加側サービスがある場合は、すべての参加側サービスでこれらのステップを完了します。

8.7 XAでのNode.jsアプリケーションの開発

8.7.1 トランザクション・イニシエータとしてのNode.jsアプリケーションの構成

トランザクション・イニシエータ・サービスは、トランザクションを開始します。トランザクション・イニシエータ・サービスは、アプリケーションのビジネス・ロジックに基づいて、トランザクションの開始のみ、またはトランザクションの開始とトランザクションへの参加を行うことができます。

開始する前に、アプリケーションがトランザクションを開始するだけか、トランザクションを開始して参加するのかを確認します。2つのシナリオでは要件が若干異なるため、それに応じてアプリケーションを構成します。

2つのシナリオを検討して、アプリケーションがトランザクションを開始するだけか、トランザクションにも参加するかを理解します。
  • シナリオ1: 銀行振込アプリケーションによって、ある部門から別の部門に送金します。この場合、振込アプリケーションはトランザクションを開始するだけで、トランザクションには参加しません。振込アプリケーションは、トランザクションを完了するためにビジネス・ロジックに基づいて様々なサービスをコールします。データベース・インスタンスは、振込アプリケーションにアタッチされる場合とアタッチされない場合があります。
  • シナリオ2: 銀行振込アプリケーションによって、ある部門から別の部門に送金します。振込アプリケーションは、トランザクションごとに手数料として1%を請求します。この場合、振込アプリケーションはトランザクションを開始して参加します。データベース・インスタンスは、トランザクション情報を保存するために振込アプリケーションにアタッチされる必要があります。
Node.jsアプリケーションをトランザクション・イニシエータとして構成するには:
  1. Node.jsのMicroTxライブラリをpackage.jsonファイルに依存関係として追加します。
    "dependencies": {
        "tmmlib-node": "file:tmmlib-node-<version>.tgz"
      }
  2. MicroTxライブラリのプロパティ値を指定します。
  3. プロパティ値を定義したtmm.propertiesファイルを渡して、マイクロサービスのMicroTxライブラリ・プロパティを構成します。
    TrmConfig.init('./tmm.properties');
  4. アプリケーション・コードを編集します:
    1. TrmUserTransactionオブジェクトを作成します。
    2. トランザクションを開始するために、作成したTrmUserTransactionオブジェクトに対してbegin()をコールします。begin()をコールするときに渡すパラメータは、アプリケーションがトランザクションを開始するだけか参加もするかによって異なります。
    3. トランザクションをコミットまたはロールバックするために、作成したTrmUserTransactionオブジェクトに対してcommit()またはrollback()をコールします。

    次の例は、utという名前のTrmUserTransactionオブジェクトを作成し、トランザクションを開始してからコミットまたはロールバックする方法を示しています。ここで、reqはリクエストを表します。

    //Step 3(a): Create a TrmUserTransaction object
    let ut: TrmUserTransaction = newTrmUserTransaction();
    try {
      //Step 3(b): Transaction demarcation - (start)
      await ut.begin(req);  //If your application only initiates the transaction and does not participate in it.
      await ut.begin(req, true);  //If your application initiates the transaction and participates in it.
    
      ... // implement business logic
      
      await ut.commit(req); //Step 3(c): Transaction demarcation - commit (end)
    
      resp.status(200).send("Transaction complete.");
    } 
    catch (e) {
      console.log("Transaction Failed: ", e);
      let message = e.message;
      try {
        console.log("Rollback on transaction failure.");
        await ut.rollback(req); //Step 3.c: Transaction rollback (end)
        message = message + ". Transaction rolled back. ";
      } catch (ex) {
        console.log("Error in rollback for transfer failure: ", ex);
      }
      resp.status(500).send(message);
    }

    例のコードは、try-catch文に実装されているため、エラーがあっても正常に処理されます。try-catch文を使用せずにサンプル・コードを実装することもできます。

  5. 変更内容を保存してからアプリケーションをデプロイします。アプリケーションのデプロイを参照してください。
イニシエータ・サービスが、トランザクションを開始するだけでなくトランザクションに参加する場合、トランザクションに参加してリソース・マネージャと通信するアプリケーションのために追加の構成を行う必要があります。トランザクション参加側としてのNode.jsアプリケーションの構成を参照してください。

8.7.2 トランザクション参加側としてのNode.jsアプリケーションの構成

リソース・マネージャがXAに準拠しているかどうかに応じて、環境変数を設定し、ライブラリから異なるクラスを実装します。

8.7.2.1 XA準拠リソース・マネージャを使用するNode.jsアプリケーションの構成

XA準拠のリソース・マネージャを使用する場合は、この項に記載されている情報を使用してNode.jsトランザクション参加側アプリケーションを構成します。

  1. Node.jsのMicroTxライブラリをpackage.jsonファイルに依存関係として追加します。
    "dependencies": {
        "tmmlib-node": "file:tmmlib-node-<version>.tgz"
      }
  2. MicroTxライブラリのプロパティ値を構成します。ライブラリ・プロパティの構成を参照してください。
    oracle.tmm.xa.XaSupportの値がtrueoracle.tmm.xa.LLRSupportの値がfalseに設定されていることを確認します。
    oracle.tmm.xa.XaSupport = true
    oracle.tmm.xa.LLRSupport = false
  3. プロパティ値を定義したtmm.propertiesファイルを渡して、マイクロサービスのMicroTxライブラリ・プロパティを構成します。
    TrmConfig.init('./tmm.properties');
  4. MicroTxライブラリをインポートします。
    import {Request, Response, Router} from 'express';
    import {XATransactionMethod, XAConfig, XADataSource, TrmXAResource} from "tmmlib-node/xa/xa";
    import {TrmConfig} from "tmmlib-node/util/trmutils";
    import {asyncHandler} from "tmmlib-node/util/asynchandler";
  5. リソース・マネージャとしてOracle Databaseを使用している場合は、さらに次のライブラリをインポートします。
    import {OracleXADataSource} from "tmmlib-node/xa/oraxa";
  6. ルーター・オブジェクトを作成します。
    たとえば、次のコードでは、bankSvcRouterという名前のルーター・オブジェクトが作成されます。一意のルーター名を指定します。
    const bankSvcRouter = Router();
  7. 次の形式を使用して、データベース接続の詳細をパラメータに指定します。
    dbConfig = export default {
    user : "database_user",
    password : "database_password",
    connectString : "database_connection_string"
    };

    説明

    • dbConfigは、作成するパラメータの名前です。
    • database_userおよびdatabase_passwordは、XA準拠のリソース・マネージャにアクセスするためのユーザー名とパスワードです。
    • connectionString: Oracle Databaseのデータ・ストアの接続文字列を入力します。
      • 非自律型Oracle Database (資格証明ウォレットを使用しないデータベース)を使用している場合は、次の形式を使用して接続文字列を入力します:
        jdbc:oracle:thin:@<publicIP>:<portNumber>/<database unique name>.<host domain name>
        たとえば:
        jdbc:oracle:thin:@123.213.85.123:1521/CustDB_iad1vm.sub05031027070.customervcnwith.oraclevcn.com
      • Oracle Database Cloud ServiceとOracle Cloud Infrastructureを一緒に使用している場合は、『Oracle Blockchain Platformの使用』Oracle Database Classic Cloud Service接続文字列の作成を参照してください。
      • Oracle Autonomous Transaction Processingを使用している場合は、次の形式を使用して接続文字列を入力します:
        jdbc:oracle:thin:@tcps://<host>:<port>/<service_name>?wallet_location=<wallet_dir>

        必要な詳細(ホスト、ポート、サービス名など)は、ウォレットを抽出したフォルダにあるtnsnames.oraファイルで確認できます。

        たとえば:

        jdbc:oracle:thin:@tcps://adb.us-phoenix-1.oraclecloud.com:7777/unique_connection_string_low.adb.oraclecloud.com?wallet_location=Database_Wallet
  8. データベース接続の詳細を含むパラメータを渡し、OracleXADataSourceオブジェクトを作成します。
    const xaPds: XADataSource = new OracleXADataSource(dbConfig);
  9. 作成したOracleXADataSourceオブジェクトをTrmXAResource.initメソッドに渡します。
    TrmXAResource.init(xaPds);
  10. getXaConnectionメソッドをコールして、データベース接続を初期化します。
    xaPds.getXAConnection();
  11. XAトランザクションに参加できる参加側サービス内のすべてのREST APIエンドポイントでXAConfigを初期化します。XAトランザクションに参加できるエンドポイント・メソッドは複数存在できます。エンドポイントごとにXATransactionMethodのインスタンスを作成し、XATransactionMethodの配列をXAConfigオブジェクトに渡します。

    次のコード・サンプルでは、/depositエンド・ポイントのオブジェクトを初期化する方法を示しています。

    
    const xaTransactionDeposit : XATransactionMethod = new XATransactionMethod("/deposit");
    const xaTransactionMethods : XATransactionMethod[] = [xaTransactionDeposit];
    const xaConfig: XAConfig = new XAConfig(bankSvcRouter, '/', xaTransactionMethods);
  12. ここではインターセプタを設定して、現在のグローバル・トランザクションで、これらのエンドポイントにコールを関与させるようにします。次のコード・サンプルでは、Express.jsルーターbankSvcRouterが、指定したエンドポイント/depositの受信リクエストを、指定した関数にルーティングする方法を示しています。
    //This is an endpoint that can participate in an XA transaction.
    bankSvcRouter.post('/deposit', (req, resp) => {
        doDeposit(req, resp); //business logic
    });
    
    async function doDeposit(req: Request, resp: Response) {
        console.log(`Nodejs department Service deposit() called`);
    //The following sample code demonstrates how you can use the connection object within your business logic. 
        let amount = 10;
        if (req.query.amount != null && typeof req.query.amount === 'string') {
            amount = parseInt(req.query.amount, 10);
        }
        // XA connection pool is created and managed by the MicroTx library
        // and is present in the context property of req object. 
        // This is available on endpoints that are part of a XA transaction.
        try {
            await req.context.xaConnection.connection.execute('UPDATE accounts SET amount = amount + :1 where account_id = :2', [amount, req.params.id]);
            resp.status(200).send();
        } catch (e: any) {
            resp.status(500).send();
        }
    }
8.7.2.2 非XAリソースを使用するNode.jsアプリケーションの構成

非XAリソース(MongoDBなど)を使用する場合は、この項に記載されている情報を使用してNode.jsトランザクション参加側アプリケーションを構成します。

非XAリソースをリソース・マネージャとして使用できるのは、1つのレプリカを含むトランザクション参加側サービスのみです。トランザクション参加側サービスに複数のレプリカがある場合は、非XAリソースを使用できません。

  1. Node.jsのMicroTxライブラリをpackage.jsonファイルに依存関係として追加します。
    "dependencies": {
        "tmmlib-node": "file:tmmlib-node-<version>.tgz"
      }
  2. MicroTxライブラリのプロパティ値を構成します。ライブラリ・プロパティの構成を参照してください。
    oracle.tmm.xa.XaSupportの値がfalseoracle.tmm.xa.LLRSupportの値がtrueに設定されていることを確認します。
    oracle.tmm.xa.XaSupport = false
    oracle.tmm.xa.LLRSupport = true
  3. プロパティ値を定義したtmm.propertiesファイルを渡して、マイクロサービスのMicroTxライブラリ・プロパティを構成します。
    TrmConfig.init('./tmm.properties');
  4. MicroTxライブラリをインポートします。
    import {Request, Response, Router} from 'express';
    import {XATransactionMethod, XAConfig, TrmConfig, NonXAResource, TrmNonXAResource} from "../trmlib/xa";
  5. ルーター・オブジェクトを作成します。
    たとえば、次のコードでは、bankSvcRouterという名前のルーター・オブジェクトが作成されます。一意のルーター名を指定します。
    const bankSvcRouter = Router();
  6. NonXAResourceインタフェースを実装します。

    たとえば、次のコード・サンプルでは、MongoDbNonXAResourceクラスによってNonXAResourceインタフェースが実装されます。

    public class MongoDbNonXAResource implements NonXAResource {
    // Provide application-specific code for all the methods in the NonXAResource interface.
    }
  7. NonXAResourceインタフェースを実装するクラスを、XA操作を処理するためのMicroTxライブラリに登録します。

    次の例では、NonXAResourceインタフェースを実装するMongoDbNonXAResourceクラスをMicroTxライブラリに登録する方法について説明します。

    const nonxaResource: NonXAResource = new MongoNonXAResource();
  8. TrmNonXAResource.init()関数を使用して、MicroTxライブラリが使用するNonXAResourceオブジェクトを指定します。
    TrmNonXAResource.init(nonxaResource)
  9. 変更内容を保存します。

8.8 トランザクション参加側としてのORDSアプリケーションの開発

この項では、Oracle Databaseサンプル・アプリケーションをデプロイして実行するというコンテキストで、データベース・アプリケーションをXA参加側として構成する詳しいステップを説明します。

MicroTxを使用したトランザクションにおいて、Oracle Databaseアプリケーションをトランザクション参加側として構成できます。Oracle ApexおよびOracle REST Data Services (ORDS)を使用して構築したOracle Databaseアプリケーションは、XAトランザクション参加側としてのみサポートされます。

データベース・アプリケーションは、Oracle Databaseを使用するOracle APEXおよびORDSのアプリケーションです。データベース・アプリケーションを実行できるのは、Oracle Cloud Infrastructureの管理対象APEXサービス、KubernetesクラスタにデプロイされたOracle RADスタック、あるいはVMまたは物理ホスト内にデプロイされたOracle RADスタックです。Oracle RADスタックは、Oracle REST Data Services (ORDS)、Oracle APEXおよびOracle Databaseの3つのコア・コンポーネントに基づいた包括的テクノロジ・スタックです。

8.8.1 前提条件

開始する前に、次のタスクを完了してください。

  • Oracle REST Data Services (ORDS)、Oracle APEXおよびOracle Databaseで構成される作業スタックを作成するか指定します。このスタックは、MicroTxが実行されるのと同じKubernetesクラスタで実行することも、他の環境で実行することもできます。
  • 同じKubernetesクラスタにデプロイしない場合は、MicroTxとデータベース・アプリケーションの間にネットワーク・アクセスまたは接続があることを確認します。
  • Oracle Databaseで既存のスキーマを使用するか、新しいスキーマを作成します。スキーマをORDSに登録していることを確認します。https://docs.oracle.com/en/database/oracle/application-express/21.1/aeutl/accessing-RESTful-services.htmlを参照してください。
  • ORDSサービスが登録したスキーマで使用できることを確認します。たとえば、http://localhost:50080/ordsです。スキーマのユーザー資格証明を使用してAPEXワークスペースにログインします。
  • アクセス制御リスト(ACL)を作成して権限を追加します(デフォルトではアウトバウンドRESTコールが許可されない場合)。

    MicroTxライブラリは、参加側サービスをXAトランザクションに登録するためのMicroTxトランザクション・コーディネータへのアウトバウンドRESTコールを行います。

    必要なACLを作成し、データベースに追加します。ACLを追加するには、sysdba権限が必要です。次に、ACLの例を示します。必要なACLの追加の詳細は、APEXのドキュメントを参照してください。

    /
    BEGIN
    DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
    host => '#TMM_HOST_NAME',
    lower_port => null,
    upper_port => null,
    ace => xs$ace_type(privilege_list => xs$name_list('connect', 'resolve', 'http'),
    principal_name => '#PRINCIPAL_NAME',
    principal_type => xs_acl.ptype_db));
    END;
    /

    ここでは、次の値を、環境に固有の値に置き換える必要があります。

    • #TMM_HOST_NAME: ホスト名またはMicroTxの外部IPアドレスを入力します。
    • #PRINCIPAL_NAME APEXのプリンシパル・ユーザーの名前を入力します。

8.8.2 SQL用のMicroTxライブラリの実行

XA向けMicroTxライブラリ(PL/SQL)には、MicroTxによって調整されるXAトランザクションにOracle Databaseアプリケーションが参加するための一連の関数およびストアド・プロシージャが用意されています。

このライブラリはSQLファイルとして用意されており、アプリケーション・コードを実行する前にこれを実行する必要があります。ライブラリをインストールするために、この1回かぎりのタスクを実行する必要があります。
  1. ORDSに登録したスキーマ・ユーザーを使用してOracle Databaseに接続します。
    SQL DeveloperまたはSQLPlusを使用して接続できます。
  2. SQL DeveloperまたはSQL Plusを使用して、tmmxa.SQLファイルを実行します。
    このファイルはinstallation_directory/otmm-RELEASE/samples/xa/plsql/libフォルダにあります。
    これによって、一連のPL/SQL関数およびストアド・プロシージャが作成されます。

8.8.3 ORDSアプリケーションの構築

TmmStart関数を使用すると、XAトランザクションをMicroTxで調整できます。MicroTxに対してRESTコールを行い、XAトランザクションに参加側を登録し、コールバックREST APIを登録します。

TmmStart関数からオブジェクトが返され、属性proceedが提供されます。これは、TmmStart関数が正常に実行されたかどうか、トランザクションを先に進められるかどうかを示します。

Proceedの値 意味
0 XAトランザクション内でTmmStart関数がコールされましたが、XAの初期化は成功しませんでした。つまり、アプリケーション・コードでXAトランザクションを進めることはできません。
1 XAトランザクション内でTmmStart関数がコールされ、XAの初期化が成功しました。つまり、アプリケーション・コードでXAトランザクションを進める必要があります。
2 MicroTx XAトランザクションがなく、ローカル・トランザクション内で関数が実行されています。つまり、アプリケーション・コードを通常どおりに進めます。

ビジネス・ロジックの実行が完了したら、TmmEnd関数をコールします。

  1. アプリケーションで必要な表やその他のデータベース・オブジェクトのためにDDLを作成します。
  2. デフォルト・データを挿入するために必要なDMLを追加します。
  3. アプリケーションの新しいRESTモジュールを作成または定義します。
  4. アプリケーションで必要なPL/SQL関数およびストアド・プロシージャを作成します。
  5. REST APIごとに、テンプレートおよびハンドラを定義します。
    1. RESTサービス・モジュールの名前およびベース・パスを入力します。次のコード例は、値としてaccountsを示しています。この値は、ご使用の環境に固有の情報で置き換えてください。
      DECLARE
          //Provide a name for the REST service module
          restModuleName VARCHAR2(256):= 'accounts'; 
          //Provide a base path for the REST service
          restModuleBasePath VARCHAR2(256):= 'accounts';
    2. l_callBackUrlの値を設定します。たとえば、http://localhost:50080/ords/ordstest/accountsです。TmmReturnのパラメータも初期化します。
      DECLARE
      //Set up the callBackUrl correctly. This is generally the base URL or path of the module.
      l_callBackUrl  VARCHAR2(256) := OWA_UTIL.get_cgi_env(''X-APEX-BASE'') || ''accounts'';
      l_tmmReturn TmmReturn;
      l_tmmReturn2 TmmReturn;
    3. TmmStartをコールします。

      次のコード・サンプルは、TmmStart関数をコールする方法を示しています。次の例に示すように、すべてのパラメータを渡します。TmmStartをコールするときに、l_callBackUrlの値を渡す必要があります。他のすべてのパラメータの値は、受信リクエスト・ヘッダーから自動的に取得されて渡されます。

      //Call TmmStart. Specify value for callBackUrl.
      l_tmmReturn := TmmStart(callBackUrl => l_callBackUrl, linkUrl => :linkUrl, requestId => :requestId, authorizationToken => :authorization, tmmTxToken => :tmmTxToken);

      TmmStart関数からオブジェクトが返され、属性proceedが提供されます。これは、TmmStart関数が正常に実行されたかどうか、トランザクションを先に進められるかどうかを示します。

    4. XAトランザクションを進めるか(l_tmmReturn.proceedの値が0より大きい)、進めないか(l_tmmReturn.proceedの値が0)を確認します。XAトランザクションをさらに進められる場合のみ、ビジネス・ロジックを実行します。それ以外の場合は、次のコード例に示すように、TmmStart関数がHTTPエラー・ステータス・コードを返す必要があります。ビジネス・ロジックの実行が完了したら、TmmEnd関数をコールします。
      IF (l_tmmReturn.proceed > 0) THEN                  
      //Execute your business logic only if the XA transaction can proceed further.
      //Execute SQLs statements or call other functions or stored procedures.
      	doWithdraw(p_amount  => :amount, p_account_id  => :accountId);
       
      	//Call TmmEnd at the end of the REST function.
      	l_tmmReturn2 := TmmEnd(p_xid => l_tmmReturn.xid);      
              :status_code := 200;
      ELSE
              :status_code := 400; --bad request
      END IF;
    5. MicroTxコールバックAPIを作成します。
      createTMMCallbacks(moduleName => restModuleName);
    6. XAトランザクションに参加するすべてのメソッド・ハンドラを登録します。
      registerXaHandler(moduleName => restModuleName,
                            handlerPattern => ':accountId/withdraw',
                            handlerMethod => 'POST');

    次のコード・サンプルは、ハンドラを実装する方法を示しています。

    DECLARE
        //Provide a name for the REST service module
        restModuleName VARCHAR2(256):= 'accounts'; 
        //Provide a base path for the REST service
        restModuleBasePath VARCHAR2(256):= 'accounts';
    
    BEGIN
        ORDS.define_module(
                p_module_name    => restModuleName,
                p_base_path      => restModuleBasePath,
                p_items_per_page => 0);
     
        ORDS.define_template(
                p_module_name    => restModuleName,
                p_pattern        => ':accountId/withdraw');
     
        ORDS.define_handler(
                p_module_name    => restModuleName,
                p_pattern        => ':accountId/withdraw',
                p_method         => 'POST',
                p_source_type    => ORDS.source_type_plsql,
                p_source         => '
                            DECLARE
                            //Set up the callBackUrl correctly. This is generally the base URL or path of the module.
                            //Example: http://localhost:50080/ords/ordstest/accounts
                            l_callBackUrl  VARCHAR2(256) := OWA_UTIL.get_cgi_env(''X-APEX-BASE'') || ''accounts''; 
                            l_tmmReturn TmmReturn;
                            l_tmmReturn2 TmmReturn;
     
                            BEGIN
                                //Call TmmStart. Pass all the other parameters than the callBackUrl.
                                l_tmmReturn := TmmStart(callBackUrl => l_callBackUrl, linkUrl => :linkUrl, requestId => :requestId, authorizationToken => :authorization, tmmTxToken => :tmmTxToken);
     
                                //Check if the transaction should proceed further
                                //(value of l_tmmReturn.proceed is greater than 0) 
                                //or not (value of l_tmmReturn.proceed is 0). 
                                //Execute your business logic only if transaction can proceed further.
                                //If not, then return with an HTTP error code.
                                IF (l_tmmReturn.proceed > 0) THEN                  
     
                                    //Execute your business logic. 
                                    //Execute SQLs statements or call other functions or stored procedures.
                                    doWithdraw(p_amount  => :amount, p_account_id  => :accountId);
     
                                    //Call TmmEnd at the end of the REST function.
                                    l_tmmReturn2 := TmmEnd(p_xid => l_tmmReturn.xid);      
     
                                    :status_code := 200;
     
                                ELSE
                                    :status_code := 400; --bad request
     
                                END IF;
     
                            exception
                                when others then
                                    :status_code := 500;
     
                             END;',
                p_items_per_page => 0);
     
     
        //Create MicroTx callback APIs.
        createTMMCallbacks(moduleName => restModuleName);
     
        //Register all method handlers that will participate in the XA transaction.
        registerXaHandler(moduleName => restModuleName,
                          handlerPattern => ':accountId/withdraw',
                          handlerMethod => 'POST');
     
    COMMIT;
    END;
    /

8.8.4 XAトランザクションの実行

XAサンプル・アプリケーションを例として使用して、XAトランザクションを実行する方法を説明します。

サンプル・アプリケーションのコードは、MicroTxのインストール・バンドルに含まれています。

  1. SQL DeveloperまたはSQL Plusを使用して、サンプル・アプリケーション(ordsapp.sqlファイル)を実行します。
    このファイルはinstallation_directory/otmm-RELEASE/samples/xa/plsql/databaseappフォルダにあります。ORDSに登録したスキーマ・ユーザーを使用してOracle Databaseに接続します。SQL DeveloperまたはSQLPlusを使用して接続できます。

    これによって、表などのデータベース・オブジェクトすべてと、一連のPL/SQL関数およびストアド・プロシージャが作成されます。また、すべてのREST APIとともにRESTモジュールも作成されます。この時点で、アプリケーションはREST APIコールを処理する準備ができています。

  2. 次のコマンドを実行して、サンプル・アプリケーションをテストします。次のサンプル・コードのwithdrawおよびdeposit REST APIへのコールは、XAトランザクションには含まれずに、アプリケーション内でローカルに実行されます。これらのサンプル・コマンドは、サンプル・アプリケーションが設計どおりに動作することをテストする場合にのみ使用します。これらのサンプル・コマンドでは、口座は222、ポートは50080です。これらの値は、ご使用の環境に固有の情報で置き換えてください。
    1. 口座222の残高を確認します。
      curl --location --request GET 'http://localhost:50080/ords/ordstest/accounts/222'
    2. 金額を10として口座222に対してwithdraw REST APIをコールします。
      curl --location --request POST 'http://localhost:50080/ords/ordstest/accounts/222/withdraw?amount=10'
    3. 口座222の残高を調べ、引出し機能が成功したかどうかを確認します。
      curl --location --request GET 'http://localhost:50080/ords/ordstest/accounts/222'
    4. 金額を10として口座222に対してdeposit REST APIをコールします。
      curl --location --request POST 'http://localhost:50080/ords/ordstest/accounts/222/deposit?amount=10'
    5. 口座222の残高を調べ、預入れ機能が成功したかどうかを確認します。振込リクエストで他の口座を使用した場合は、222のかわりに正しい口座を使用します。
      curl --location --request GET 'http://localhost:50080/ords/ordstest/accounts/222'
  3. イニシエータ・アプリケーションでORDSアプリケーションをXA参加側として構成します。このデータベース・アプリケーションを、他のXAサンプル・アプリケーションを含むMicroTxを使用するXAトランザクションの参加側として使用するには、次に示すように変更します。
    //In the deployment descriptor for the accounts service, 
    //modify the env variable departmentTwoEndpoint value to the 
    //ORDS application URL "https://host:port/ords/schema/accounts". 
                name: departmentTwoEndpoint
                value: https://host:port/ords/schema/accounts

    ここで、schemaはORDSに登録したスキーマです。

  4. XAトランザクションを実行します。XAトランザクションの実行を参照してください。