2.3.2 複数のDBMSを対象にトランザクション制御を行う方法(TPBrokerのOTS機能を使用する場合)

この方法では,DBMSへのアクセスは一つのDBMSを対象にトランザクション制御を行う方法と同じで,トランザクション制御の部分でTPBroker for C++が提供するOTS機能を使用します。

OTS機能はRed Hat Linux版では使用できません。

<この項の構成>
(1) 動作概要
(2) リソースマネジャの動作環境の設定(①)
(3) リソースマネジャの登録(②)
(4) アプリケーションでの処理手続き(③,④)
(5) グローバルトランザクション(⑤)
(6) サンプルコーディング
(7) DBStatementオブジェクトの使用可能範囲

(1) 動作概要

複数のDBMSを対象にトランザクション制御を行う場合の動作概要を図2-1に示します。TPBrokerのトランザクション制御では, X/Openで規定されたDTPモデルに準拠し,ユーザアプリケーションをアプリケーションプログラムAP),DBMSをリソースマネジャRM),トランザクション制御を行うTPBrokerをトランザクションマネジャTM)と呼びます。

図2-1 複数のDBMSを対象にトランザクション制御を行う場合の動作概要

[図データ]

複数DBMSに対してトランザクション制御する場合(③)は,TPBrokerのメソッドを使ってトランザクションの開始・決着を記述し,その間のDBMSへのアクセス(④)はDABroker for C++のメソッドを使います。このときDABroker for C++のメソッドの延長でDABrokerがトランザクション識別子を取得し,SQLへ付加してDBMSへアクセスします。つまり,DABroker for C++のメソッドを使用するCORBAオブジェクトは別々であっても,トランザクション識別子が引き継がれるような仕組みになっています。

次に図2-1の丸付き数字の順に,必要になる準備,アプリケーションの処理手続きなどを説明します。TPBrokerのコマンドの詳細についてはTPBrokerのマニュアル「トランザクショナル分散オブジェクト基盤TPBrokerユーザーズガイド」を参照してください。

(2) リソースマネジャの動作環境の設定(①)

TPBrokerの機能(コマンドなど)を使用してリソースマネジャ(DBMS)のXAインタフェースを利用するために必要な情報をTPBrokerのシステム定義へ設定します。

TPBrokerのシステム定義には,システム環境定義やプロセス監視定義があります。DBMSごとに固有な情報なので,使用するDBMSのドキュメントを参照して登録してください。

例えば,システム環境定義の中のリソースマネジャ定義では,X/Openの規格に従った,オープン文字列,クローズ文字列,環境変数などDBMSで解釈される情報を設定します。設定にはTPBrokerのtskeycreate,tsdefvalueコマンドを使います。

(3) リソースマネジャの登録(②)

アプリケーションで使用するリソースマネジャ(DBMS)をトランザクションマネジャへTPBrokerのtslnkrmコマンドを使って登録します。登録方法には,動的登録と静的登録があります。

(4) アプリケーションでの処理手続き(③,④)

(a) グローバルトランザクションの開始・決着

アプリケーションでは,TPBrokerが提供するメソッドを使ってトランザクションの開始と決着を記述します。このトランザクションのことをTPBrokerではグローバルトランザクションと呼んでいます。

グローバルトランザクションの開始と決着はTPBrokerが提供する次のメソッドを使います。

処理使用するTPBroker提供のメソッド
開始CosTransactions::Current::begin()メソッド
決着(コミット)CosTransactions::Current::commit()メソッド
決着(ロールバック)CosTransactions::Current::rollback()メソッド
(b) DBMSへのアクセス手続き

DBMSへのアクセスは,一つのDBMSを対象にトランザクション制御を行う方法と同様ですが,オブジェクトの生成方法が一部変わります。詳細は次の個所を参照してください。

この指定によって,そのオブジェクト,すなわちDBMSへのアクセスはグローバルトランザクションの制御対象になるわけです。指定しない場合は対象からはずれるので,DABrokerが提供しているトランザクション用のメソッド(DBTransaction)を使って制御します。

(c) アプリケーションのリンケージ

作成したアプリケーションのリンケージの際に,次の三つのオブジェクトファイルを付け加えてください。

(5) グローバルトランザクション(⑤)

グローバルトランザクションの開始によってトランザクションの識別子が付与され,アプリケーションとDBMSの間でのアクセスは同じトランザクションの識別子で管理されます。コミットによって該当する識別子を対象にXAインタフェースを使ってトランザクションマネジャとDBMSの間で2相コミットプロトコルが実行されます。

(6) サンプルコーディング

(例1)簡易版クラスのトランザクション

////////////////////////////////////////////////////////////
///  TPBrokerによるトランザクション制御(簡易版)
#include "tsport_c.hh"
#include "tpcosots_c.hh"
#include "dbbroker.h"

DBRDatabase *pDB1
DBRDatabase *pDB2

int main(int argc,char* argv[])
{
 pDB1 = NULL;
 pDB2 = NULL;

 try
 {
   CORBA::ORB_var orb=CORBA::ORB_init(argc,argv);
   CORBA::BOA_var boa=orb->BOA_init(argc,argv);
   CORBA::Object_var obj=orb->resolve_initial_referrences
                                  ("TransactionCurrent");
   CosTransactions::Current_var current=
                  CosTransactions::Current::_narrow(obj);

current->begin();   // グローバルトランザクションの開始

   try
   {
     pDB1 = new DBRDatabase(DRV_TYPE_ORACLE7,"XA");
     pDB1->Connect("orauser", "orapw1", "ORA1");
     pDB1->ExecuteDirect("INSERT INTO SAMPLETABLE
                                       VALUES(1,'ABC')");

     pDB2 = new DBRDatabase(DRV_TYPE_ORACLE7,"XA");
     pDB2->Connect("orauser2", "orapw2", "ORA2");
     pDB2->ExecuteDirect("INSERT INTO SAMPLETABLE2
                                       VALUES(2,'DEF')");

current->commit(1);
            // グローバルトランザクションのコミット

     pDB1->Close();
     pDB2->Close();
  }
  catch (DBSQLCA& ca)
  {
    current->rollback();
            // グローバルトランザクションのコミット
    // エラー処理
  }
 }
 catch(CORBA::SystemExecution se)
 {
   //  エラー処理
 }
 if(pDB1)
   delete pDB1;
 if(pDB2)
   delete pDB2;
 return();
}

(例2)詳細版クラスのトランザクション

///////////////////////////////////////////////////////////
///  TPBrokerによるトランザクション制御(詳細版)
#include "tsport_c.hh"
#include "tpcosots_c.hh"
#include "dbbroker.h"

DBDriverManager * pDrvMan;

int main(int argc, char* argv[])
{
 pDrvMan = NULL;
 try
 {
   CORBA::ORB_var  orb = CORBA::ORB_init(argc, argv);
   CORBA::BOA_var  boa = orb->BOA_init(argc, argv);
   CORBA::Object_var  obj = orb->resolve_initial_references
                                   ("TransactionCurrent");;
   CosTransactions::Current_var  current =
                    CosTransactions::Current::_narrow(obj);

   current->begin();    // グローバルトランザクションの開始

   try
   {
     pDrvMan = new DBDriverManager;
     pDrvMan->InitializeMessage();

// OTS機能を使用したトランザクション制御の使用
     DBDriver*  pDriver =
                   pDrvMan->Driver(DRV_TYPE_ORACLE7,"XA");

     DBConnection*  pConnect1 = pDriver->Connect
                ("Sample1", "orauser1", "orapw1", "ORA1");
     DBConnection*  pConnect2 = pDriver->Connect
                ("Sample2", "orauser2" , "orapw2","ORA2");
     pConnect1->ExecuteDirect
             ("INSERT INTO SAMPLETABLE VALUES (1,'ABC')");
     pConnect2->ExecuteDirect
             ("INSERT INTO SAMPLETABLE VALUES (2,'DEF')");

     current->commit(1);     // トランザクションのコミット

     pConnect1->Close();
     pConnect2->Close();
   }
   catch (DBSQLCA& ca)
   {
     current->rollback();
                        // トランザクションのロールバック
     //エラー処理
   }
 }
 catch (CORBA::SystemException se)
 {
   //エラー処理
 }
 if(pDrvMan)
   delete pDrvMan;
 return 0;
}

(7) DBStatementオブジェクトの使用可能範囲

DBStatementオブジェクト,DBPreparedStatementオブジェクト,DBCallableStatementオブジェクトについては,複数のサーバメソッド間で共有しないようにしてください。同じRMに対する操作であっても,異なるスレッドで起動されたメソッドでは正常に動作しません。あるメソッドで生成したDBStatementオブジェクト(DBPreparedStatementオブジェクト,DBCallableStatementオブジェクト)はそのメソッド内で削除するようにしてください。