6.10 トランザクション参加側としての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つのコア・コンポーネントに基づいた包括的テクノロジ・スタックです。

6.10.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のプリンシパル・ユーザーの名前を入力します。

6.10.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関数およびストアド・プロシージャが作成されます。

6.10.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;
    /

6.10.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トランザクションの実行を参照してください。