プライマリ・コンテンツに移動
Oracle® Call Interfaceプログラマーズ・ガイド
12c リリース1 (12.1)
B72465-07
目次へ移動
目次
索引へ移動
索引

前
次

トランザクション関数

表17-6は、この項で説明しているトランザクション関数を示しています。

表17-6 トランザクション関数

関数 用途

「OCITransCommit()」

サービス・コンテキスト上のトランザクションをコミットします。

「OCITransDetach()」

サービス・コンテキストからトランザクションを連結解除します。

「OCITransForget()」

準備したグローバル・トランザクションを放棄します。

「OCITransMultiPrepare()」

単一セルに複数のブランチがあるトランザクションを準備します。

「OCITransPrepare()」

グローバル・トランザクションをコミットのために準備します。

「OCITransRollback()」

トランザクションをロールバックします。

「OCITransStart()」

サービス・コンテキスト上のトランザクションを開始します。

OCITransCommit()

指定のサービス・コンテキストに対応付けられたトランザクションをコミットします。

用途

指定のサービス・コンテキストに対応付けられたトランザクションをコミットします。

構文

sword OCITransCommit ( OCISvcCtx    *svchp,
                       OCIError     *errhp,
                       ub4           flags );

パラメータ

svchp (IN)

サービス・コンテキスト・ハンドルです。

errhp (IN)

エラー発生時の診断情報のためにOCIErrorGet()に渡すエラー・ハンドルです。

flags (IN)

グローバル・トランザクションの1フェーズ・コミットを最適化するためのフラグです。

OCI_DEFAULT - トランザクションが分散型でない場合、flagsパラメータは無視され、その値としてOCI_DEFAULTを渡すことができます。

OCI_TRANS_TWOPHASE- 2フェーズ・コミットでは、グローバル・トランザクションを管理しているOCIアプリケーションは、flagsに対してこの値を渡す必要があります。デフォルトは1フェーズ・コミットです。

OCI_TRANS_WRITEIMMED- (インメモリー)REDOバッファをオンラインREDOログに書き込むためのI/OがLGWR (バックグラウンドのログ・ライター・プロセス)によって開始されます。IMMEDIATEとは、メッセージをLGWRに送信してLGWRでメッセージを即時に処理し、トランザクションのREDOバッファを即時に書き出すことを示します。

OCI_TRANS_WRITEBATCH- トランザクションのインメモリーREDOバッファをオンラインREDOログに書き込むためのI/OはLGWRによって発行されません。BATCHは、LGWRがREDOバッファをバッチ処理してからバッチ全体に対してI/Oを開始することを示します。BATCHIMMEDIATEの両方を指定するとエラーが発生します。デフォルトはIMMEDIATEです。

OCI_TRANS_WRITEWAIT - これは、コミットのREDOバッファをオンラインREDOログに書き込むようLGWRに要求し、書き込まれるまではコミットを待機させます。WAITとは、トランザクションに対応するインメモリーREDOバッファが永続オンラインREDOログに書き込まれて初めてコミットが終了することを示します。

OCI_TRANS_WRITENOWAIT- これは、コミットのREDOバッファをオンラインREDOログに書き込むようLGWRに要求しますが、バッファがオンラインREDOログに書き込まれるのを待たずにコミットは終了します。NOWAITとは、インメモリーREDOバッファをオンラインREDOログにフラッシュせずにコミットが終了することを示します。WAITNOWAITの両方を指定するとエラーが発生します。デフォルトはWAITです。

注意:

OCI_TRANS_WRITENOWAITを使用すると、警告なしでトランザクションが消失する可能性があります。トランザクションの消失は、強制停止、強制起動、およびインスタンス障害やノード障害によって、警告なしに発生します。Oracle RACシステムでは、非同期にコミットされた場合、他のインスタンスでその変更を即時に読み取れない場合があります。

これら最後の4つのオプションは、分散型でないトップレベルのトランザクションのコミットのみに影響し、外部協調分散トランザクションでは無視されます。これらのオプションは、指定されている制限内容に応じてOR演算子を使用して結合できます。

コメント

サービス・コンテキストに現在対応付けられているトランザクションをコミットします。トランザクションがサーバーによるコミットが不可能なグローバル・トランザクションである場合、このコールは、トランザクションの状態をデータベースから取り出し、エラー・ハンドルを使用してユーザーに戻します。

複数のトランザクションを定義している場合、この関数は、サービス・コンテキストに現在対応付けられているトランザクションを処理します。データベースの変更時に作成される暗黙的ローカル・トランザクションのみを処理している場合は、その暗黙的トランザクションがコミットされます。

アプリケーションをオブジェクト・モードで実行している場合は、このトランザクションに対してオブジェクト・キャッシュで変更または更新されたオブジェクトもフラッシュされ、コミットされます。

正常な状況では、OCITransCommit()は、トランザクションがコミットされたかロールバックされたかを示す状態を戻します。グローバル・トランザクションでは、トランザクションがインダウトの状態、つまり、コミットも終了もされていない状態の場合もあり得ます。この場合、OCITransCommit()は、トランザクションの状態をサーバーから取り出します。そのステータスが戻ります。

次のコード例は、「単純なローカル・トランザクション」に記述されている単純なローカル・トランザクションの使用方法を説明しています。

単純なローカル・トランザクションでのOCITransCommit()の使用

int main()
{
  OCIEnv *envhp;
  OCIServer *srvhp;
  OCIError *errhp;
  OCISvcCtx *svchp;
  OCIStmt *stmthp;
  void      *tmp;
  text sqlstmt[128];

  OCIEnvCreate(&envhp, OCI_DEFAULT, (void  *)0, 0, 0, 0,
        (size_t)0, (void  *)0);

  OCIHandleAlloc( (void  *) envhp, (void  **) &errhp, (ub4) OCI_HTYPE_ERROR,
                (size_t)0, (void  **) 0);
  OCIHandleAlloc( (void  *) envhp, (void  **) &srvhp, (ub4) OCI_HTYPE_SERVER,
                (size_t)0, (void  **) 0);

  OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT);

  OCIHandleAlloc( (void  *) envhp, (void  **) &svchp, (ub4) OCI_HTYPE_SVCCTX,
                (size_t)0, (void  **) 0);

  OCIHandleAlloc((void  *)envhp, (void  **)&stmthp, OCI_HTYPE_STMT, 0, 0);

  OCIAttrSet((void  *)svchp, OCI_HTYPE_SVCCTX, (void  *)srvhp, 0,
                  OCI_ATTR_SERVER, errhp);

  OCILogon(envhp, errhp, &svchp, (text *)"HR", strlen("HR"),
                 (text *)"HR", strlen("HR"), 0, 0);

  /* update hr.employees employee_id=7902, increment salary */
  sprintf((char *)sqlstmt, "UPDATE EMPLOYEES SET SALARY = SALARY + 1 \
                                            WHERE  EMPLOYEE_ID = 7902");

  OCIStmtPrepare(stmthp, errhp, sqlstmt, strlen((char *)sqlstmt),
                 OCI_NTV_SYNTAX, 0);
  OCIStmtExecute(svchp, stmthp, errhp, 1, 0, 0, 0, 0);
  OCITransCommit(svchp, errhp, (ub4) 0);

  /* update hr.employees employee_id=7902, increment salary again, but rollback */
  OCIStmtExecute(svchp, stmthp, errhp, 1, 0, 0, 0, 0);
  OCITransRollback(svchp, errhp, (ub4) 0);
}

OCITransDetach()

用途

グローバル・トランザクションの連結を解除します。

構文

sword OCITransDetach ( OCISvcCtx    *svchp,
                       OCIError     *errhp,
                       ub4          flags );

パラメータ

svchp (IN)

サービス・コンテキスト・ハンドルです。

errhp (IN)

エラー発生時の診断情報のためにOCIErrorGet()に渡すエラー・ハンドルです。

flags (IN)

このパラメータ用に値OCI_DEFAULTを渡す必要があります。

コメント

サービス・コンテキスト・ハンドルからグローバル・トランザクションを連結解除します。このコールが終了した時点で、サービス・コンテキスト・ハンドルに現在連結されているトランザクションが非活動状態になります。このトランザクションは、後でOCITransStart()をコールしながらOCI_TRANS_RESUMEのフラグ値を指定するときに再開できます。

トランザクションの連結が解除されると、トランザクションの開始時にOCITransStart()timeoutパラメータに指定された値を使用して、サーバーのPMONプロセスによって削除されるまでブランチを非活動状態にしておける時間が判断されます。

注意:

トランザクションが同一の認可を持っている場合、トランザクションはその連結を解除したプロセス以外のプロセスによっても再開できます。トランザクションが実際に開始される前にこの関数がコールされると、この関数は何も行いません。

OCITransDetach()の使用方法を説明するコード例については、OCITransStart()の例の項を参照してください。

関連関数

OCITransStart()

OCITransForget()

用途

完了したグローバル・トランザクションをサーバーに放棄させます。

構文

sword OCITransForget ( OCISvcCtx     *svchp, 
                       OCIError      *errhp,
                       ub4           flags );

パラメータ

svchp (IN)

トランザクションが常駐するサービス・コンテキスト・ハンドルです。

errhp (IN)

エラー発生時の診断情報のためにOCIErrorGet()に渡すエラー・ハンドルです。

flags (IN)

このパラメータ用にOCI_DEFAULTを渡す必要があります。

コメント

完了したグローバル・トランザクションを放棄します。サーバーにより、システムのペンディング・トランザクション表からトランザクションの状態が削除されます。

放棄されるトランザクションのXIDをトランザクション・ハンドルの属性として設定します(OCI_ATTR_XID)。

OCITransMultiPrepare()

用途

単一セルに複数のブランチがあるトランザクションを準備します。

構文

sword OCITransMultiPrepare ( OCISvcCtx   *svchp, 
                             ub4         numBranches, 
                             OCITrans    **txns, 
                             OCIError    **errhp);

パラメータ

srvchp (IN)

サービス・コンテキスト・ハンドルです。

numBranches (IN)

ブランチの数を指定します。この値は、次の2つのパラメータの配列サイズでもあります。

txns (IN)

準備するブランチのトランザクション・ハンドルの配列です。これらにはすべてOCI_ATTR_XIDが設定されます。グローバル・トランザクションIDは同じにしてください。

errhp (IN)

エラー・ハンドルの配列です。OCI_SUCCESSが戻されない場合、このパラメータによってどのブランチがどのエラーを受信したか示されます。

コメント

指定のグローバル・トランザクションをコミットできるように準備します。このコールは、分散トランザクションに対してのみ有効です。このコールは、コール元がトランザクションですべてのブランチを準備する場合にかぎり使用する拡張パフォーマンス機能です。

関連関数

OCITransPrepare()

OCITransPrepare()

用途

グローバル・トランザクションをコミットのために準備します。

構文

sword OCITransPrepare ( OCISvcCtx    *svchp, 
                        OCIError     *errhp,
                        ub4          flags );

パラメータ

svchp (IN)

サービス・コンテキスト・ハンドルです。

errhp (IN)

エラー発生時の診断情報のためにOCIErrorGet()に渡すエラー・ハンドルです。

flags (IN)

このパラメータ用にOCI_DEFAULTを渡す必要があります。

コメント

指定のグローバル・トランザクションをコミットできるように準備します。

このコールは、グローバル・トランザクションに対してのみ有効です。

このコールは、トランザクションが変更されていない場合はOCI_SUCCESS_WITH_INFOを戻します。エラー・ハンドルは、トランザクションが読取り専用であることを示します。flagsパラメータは、現在使用されていません。

OCITransRollback()

用途

カレント・トランザクションをロールバックします。

構文

sword OCITransRollback ( void         *svchp, 
                         OCIError     *errhp,
                         ub4          flags );

パラメータ

svchp (IN)

サービス・コンテキスト・ハンドルです。サービス・コンテキスト・ハンドル内に現在設定されているトランザクションがロールバックされます。

errhp (IN)

エラー発生時の診断情報のためにOCIErrorGet()に渡すエラー・ハンドルです。

flags (IN)

このパラメータ用に値OCI_DEFAULTを渡す必要があります。

コメント

カレント・トランザクション(最後のOCITransCommit()、またはOCISessionBegin()以降に実行された一連の文として定義されます)がロールバックされます。

アプリケーションがオブジェクト・モードで実行されている場合は、このトランザクションで修正または更新されたオブジェクト・キャッシュ内のオブジェクトも同様にロールバックされます。

現在アクティブでないグローバル・トランザクションをロールバックしようとすると、エラーになります。

OCITransRollback()の使用方法を説明するコード例については、OCITransCommit()の例の項を参照してください。

関連関数

OCITransCommit()

OCITransStart()

用途

トランザクションの開始を設定します。

構文

sword OCITransStart ( OCISvcCtx    *svchp, 
                      OCIError     *errhp, 
                      uword        timeout,
                      ub4          flags );

パラメータ

svchp (IN/OUT)

サービス・コンテキスト・ハンドルです。flagsパラメータに新規トランザクションの開始が指定されている場合は、このコールの終了時点で、サービス・コンテキスト・ハンドル内のトランザクション・コンテキストが初期化されます。

errhp (IN/OUT)

OCIエラー・ハンドルです。エラーがある場合は、errに記録され、OCI_ERRORが戻されます。OCIErrorGet()のコールによって診断情報を取得できます。

timeout (IN)

OCI_TRANS_RESUMEが指定されたときに、トランザクションが再開できるようになるまで待機する時間(秒)です。OCI_TRANS_NEWが指定されると、timeoutパラメータの指示する秒数間、非活動状態が続いたトランザクションは、システムによって自動的に終了します。トランザクションは、OCITransDetach()による連結解除から、OCITransStart()による再開までの間、非活動状態になります。

flags (IN)

新規トランザクションが開始中か、または既存のトランザクションが再開中であるかを指定します。シリアライズ可能または読取り専用ステータスも指定します。複数の値を指定できます。デフォルトでは、読取りトランザクションまたは書込みトランザクションが開始されます。フラグ値は次のとおりです。

  • OCI_TRANS_NEW - 新規トランザクション・ブランチを開始します。デフォルトでは、密結合された移行可能なブランチが開始されます。

  • OCI_TRANS_TIGHT - 密結合ブランチを明示的に指定します。

  • OCI_TRANS_LOOSE - 疎結合ブランチを指定します。

  • OCI_TRANS_RESUME - 既存のトランザクション・ブランチを再開します。

  • OCI_TRANS_READONLY - 読取り専用トランザクションを開始します。

  • OCI_TRANS_SERIALIZABLE - シリアライズ可能トランザクションを開始します。

  • OCI_TRANS_SEPARABLE - 各コール後にトランザクションを分離します。

    このフラグは、標準のトランザクションを使用してトランザクションが開始されたという警告を示します。リリース9.0.1のサーバーでは、分離されたトランザクションはサポートされていません。

コードまたはトランザクション・サービスにエラーがある場合は、エラー・メッセージが表示されます。このエラーは、すでに準備されていたトランザクションで処理を試みたことを示します。

コメント

この関数は、グローバル・トランザクションまたはシリアライズ可能トランザクションの開始を設定します。flagsパラメータに新規トランザクションの開始が指定されている場合は、このコールの終了時点で、サービス・コンテキスト・ハンドルに現在対応付けられているトランザクション・コンテキストが初期化されます。

トランザクションのXIDがトランザクション・ハンドルの属性として設定されます(OCI_ATTR_XID)。

次とその次のコード例は、OCIトランザクション・コールを使用してグローバルなトランザクションを操作する方法を示しています。次のコード例が示すような、様々なブランチで動作するシングル・セッションの概念は図8-2で示しています。

様々なブランチで動作するシングル・セッションでのOCITransStart()の使用

int main()
{
  OCIEnv *envhp;
  OCIServer *srvhp;
  OCIError *errhp;
  OCISvcCtx *svchp;
  OCISession *usrhp;
  OCIStmt *stmthp1, *stmthp2;
  OCITrans *txnhp1, *txnhp2;
  void      *tmp;
  XID gxid;
  text sqlstmt[128];

  OCIEnvCreate(&envhp, OCI_DEFAULT, (void  *)0, 0, 0, 0,
        (size_t)0, (void  *)0);

  OCIHandleAlloc( (void  *) envhp, (void  **) &errhp, (ub4)
                OCI_HTYPE_ERROR, 52, (void  **) &tmp);
  OCIHandleAlloc( (void  *) envhp, (void  **) &srvhp, (ub4)
               OCI_HTYPE_SERVER, 52, (void  **) &tmp);

  OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT);

  OCIHandleAlloc( (void  *) envhp, (void  **) &svchp, (ub4) OCI_HTYPE_SVCCTX,
                52, (void  **) &tmp);

  OCIHandleAlloc((void  *)envhp, (void  **)&stmthp1, OCI_HTYPE_STMT, 0, 0);
  OCIHandleAlloc((void  *)envhp, (void  **)&stmthp2, OCI_HTYPE_STMT, 0, 0);

  OCIAttrSet((void  *)svchp, OCI_HTYPE_SVCCTX, (void  *)srvhp, 0,
                  OCI_ATTR_SERVER, errhp);

  /* set the external name and internal name in server handle */
  OCIAttrSet((void  *)srvhp, OCI_HTYPE_SERVER, (void  *) "demo", 0,
                  OCI_ATTR_EXTERNAL_NAME, errhp);
  OCIAttrSet((void  *)srvhp, OCI_HTYPE_SERVER, (void  *) "txn demo", 0,
                          OCI_ATTR_INTERNAL_NAME, errhp);

  /* allocate a user context handle */
  OCIHandleAlloc((void  *)envhp, (void  **)&usrhp, (ub4) OCI_HTYPE_SESSION,
                (size_t) 0, (void  **) 0);

  OCIAttrSet((void  *)usrhp, (ub4)OCI_HTYPE_SESSION, (void  *)"HR",
             (ub4)strlen("HR"), OCI_ATTR_USERNAME, errhp);
  OCIAttrSet((void  *)usrhp, (ub4)OCI_HTYPE_SESSION, (void  *)"HR",
             (ub4)strlen("HR"),OCI_ATTR_PASSWORD, errhp);

  OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS, 0);

  OCIAttrSet((void  *)svchp, (ub4)OCI_HTYPE_SVCCTX,
                (void  *)usrhp, (ub4)0, OCI_ATTR_SESSION, errhp);

  /* allocate transaction handle 1 and set it in the service handle */
  OCIHandleAlloc((void  *)envhp, (void  **)&txnhp1,  OCI_HTYPE_TRANS, 0, 0);
  OCIAttrSet((void  *)svchp, OCI_HTYPE_SVCCTX, (void  *)txnhp1, 0,
                          OCI_ATTR_TRANS, errhp);

  /* start a transaction with global transaction id = [1000, 123, 1] */
  gxid.formatID = 1000; /* format id = 1000 */
  gxid.gtrid_length = 3; /* gtrid = 123 */
  gxid.data[0] = 1; gxid.data[1] = 2; gxid.data[2] = 3;
  gxid.bqual_length = 1; /* bqual = 1 */
  gxid.data[3] = 1;

  OCIAttrSet((void  *)txnhp1, OCI_HTYPE_TRANS, (void  *)&gxid, sizeof(XID),
                          OCI_ATTR_XID, errhp);

  /* start global transaction 1 with 60-second time to live when detached */
  OCITransStart(svchp, errhp, 60, OCI_TRANS_NEW);

  /* update hr.employees employee_id=7902, increment salary */
  sprintf((char *)sqlstmt, "UPDATE EMPLOYEES SET SALARY = SALARY + 1 \
                                           WHERE EMPLOYEE_ID = 7902");
  OCIStmtPrepare(stmthp1, errhp, sqlstmt, strlen((char *)sqlstmt),
                 OCI_NTV_SYNTAX, 0);
  OCIStmtExecute(svchp, stmthp1, errhp, 1, 0, 0, 0, 0);

  /* detach the transaction */
  OCITransDetach(svchp, errhp, 0);

  /* allocate transaction handle 2 and set it in the service handle */
  OCIHandleAlloc((void  *)envhp, (void  **)&txnhp2,  OCI_HTYPE_TRANS, 0, 0);

  OCIAttrSet((void  *)svchp, OCI_HTYPE_SVCCTX, (void  *)txnhp2, 0,
                          OCI_ATTR_TRANS, errhp);

  /* start a transaction with global transaction id = [1000, 124, 1] */
  gxid.formatID = 1000; /* format id = 1000 */
  gxid.gtrid_length = 3; /* gtrid = 124 */
  gxid.data[0] = 1; gxid.data[1] = 2; gxid.data[2] = 4;
  gxid.bqual_length = 1; /* bqual = 1 */
  gxid.data[3] = 1;

  OCIAttrSet((void  *)txnhp2, OCI_HTYPE_TRANS, (void  *)&gxid, sizeof(XID),
                          OCI_ATTR_XID, errhp);

  /* start global transaction 2 with 90 second time to live when detached */
  OCITransStart(svchp, errhp, 90, OCI_TRANS_NEW);

  /* update hr.employees employee_id=7934, increment salary */
  sprintf((char *)sqlstmt, "UPDATE EMPLOYEES SET SALARY = SALARY + 1 \
                                            WHERE EMPLOYEE_ID = 7934");
  OCIStmtPrepare(stmthp2, errhp, sqlstmt, strlen((char *)sqlstmt),
                 OCI_NTV_SYNTAX, 0);
  OCIStmtExecute(svchp, stmthp2, errhp, 1, 0, 0, 0, 0);

  /* detach the transaction */
  OCITransDetach(svchp, errhp, 0);

  /* Resume transaction 1, increment salary and commit it */
  /* Set transaction handle 1 into the service handle */
  OCIAttrSet((void  *)svchp, OCI_HTYPE_SVCCTX, (void  *)txnhp1, 0,
                          OCI_ATTR_TRANS, errhp);

  /* attach to transaction 1, wait for 10 seconds if the transaction is busy */
  /* The wait is clearly not required in this example because no other */
  /* process/thread is using the transaction. It is only for illustration */
  OCITransStart(svchp, errhp, 10, OCI_TRANS_RESUME);
  OCIStmtExecute(svchp, stmthp1, errhp, 1, 0, 0, 0, 0);
  OCITransCommit(svchp, errhp, (ub4) 0);

  /* attach to transaction 2 and commit it */
  /* set transaction handle2 into the service handle */
  OCIAttrSet((void  *)svchp, OCI_HTYPE_SVCCTX, (void  *)txnhp2, 0,
                          OCI_ATTR_TRANS, errhp);
  OCITransCommit(svchp, errhp, (ub4) 0);
}

同じトランザクションを共有する複数のブランチで動作するシングル・セッションでのOCITransStart()の使用

int main()
{
  OCIEnv *envhp;
  OCIServer *srvhp;
  OCIError *errhp;
  OCISvcCtx *svchp;
  OCISession *usrhp;
  OCIStmt *stmthp;
  OCITrans *txnhp1, *txnhp2;
  void      *tmp;
  XID gxid;
  text sqlstmt[128];

  OCIEnvCreate(&envhp, OCI_DEFAULT, (void  *)0, 0, 0, 0,
        (size_t)0, (void  *)0);

  OCIHandleAlloc( (void  *) envhp, (void  **) &errhp, (ub4) OCI_HTYPE_ERROR,
                52, (void  **) &tmp);
  OCIHandleAlloc( (void  *) envhp, (void  **) &srvhp, (ub4) OCI_HTYPE_SERVER,
                52, (void  **) &tmp);

  OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0, (ub4) OCI_DEFAULT);

  OCIHandleAlloc( (void  *) envhp, (void  **) &svchp, (ub4) OCI_HTYPE_SVCCTX,
                52, (void  **) &tmp);

  OCIHandleAlloc((void  *)envhp, (void  **)&stmthp, OCI_HTYPE_STMT, 0, 0);

  OCIAttrSet((void  *)svchp, OCI_HTYPE_SVCCTX, (void  *)srvhp, 0,
                  OCI_ATTR_SERVER, errhp);

  /* set the external name and internal name in server handle */
  OCIAttrSet((void  *)srvhp, OCI_HTYPE_SERVER, (void  *) "demo", 0,
                  OCI_ATTR_EXTERNAL_NAME, errhp);
  OCIAttrSet((void  *)srvhp, OCI_HTYPE_SERVER, (void  *) "txn demo2", 0,
                  OCI_ATTR_INTERNAL_NAME, errhp);

  /* allocate a user context handle */
  OCIHandleAlloc((void  *)envhp, (void  **)&usrhp, (ub4) OCI_HTYPE_SESSION,
                (size_t) 0, (void  **) 0);

  OCIAttrSet((void  *)usrhp, (ub4)OCI_HTYPE_SESSION, (void  *)"HR",
             (ub4)strlen("HR"), OCI_ATTR_USERNAME, errhp);
  OCIAttrSet((void  *)usrhp, (ub4)OCI_HTYPE_SESSION, (void  *)"HR",
             (ub4)strlen("HR"),OCI_ATTR_PASSWORD, errhp);

  OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS, 0);

  OCIAttrSet((void  *)svchp, (ub4)OCI_HTYPE_SVCCTX,
                (void  *)usrhp, (ub4)0, OCI_ATTR_SESSION, errhp);

  /* allocate transaction handle 1 and set it in the service handle */
  OCIHandleAlloc((void  *)envhp, (void  **)&txnhp1,  OCI_HTYPE_TRANS, 0, 0);
  OCIAttrSet((void  *)svchp, OCI_HTYPE_SVCCTX, (void  *)txnhp1, 0,
                          OCI_ATTR_TRANS, errhp);

  /* start a transaction with global transaction id = [1000, 123, 1] */
  gxid.formatID = 1000; /* format id = 1000 */
  gxid.gtrid_length = 3; /* gtrid = 123 */
  gxid.data[0] = 1; gxid.data[1] = 2; gxid.data[2] = 3;
  gxid.bqual_length = 1; /* bqual = 1 */
  gxid.data[3] = 1;

  OCIAttrSet((void  *)txnhp1, OCI_HTYPE_TRANS, (void  *)&gxid, sizeof(XID),
                          OCI_ATTR_XID, errhp);

  /* start global transaction 1 with 60-second time to live when detached */
  OCITransStart(svchp, errhp, 60, OCI_TRANS_NEW);

  /* update hr.employees employee_id=7902, increment salary */
  sprintf((char *)sqlstmt, "UPDATE EMPLOYEES SET SALARY = SALARY + 1 \
                                            WHERE EMPLOYEE_ID = 7902");
  OCIStmtPrepare(stmthp, errhp, sqlstmt, strlen((char *)sqlstmt),
                 OCI_NTV_SYNTAX, 0);
  OCIStmtExecute(svchp, stmthp, errhp, 1, 0, 0, 0, 0);

  /* detach the transaction */
  OCITransDetach(svchp, errhp, 0);

  /* allocate transaction handle 2 and set it in the service handle */
  OCIHandleAlloc((void  *)envhp, (void  **)&txnhp2,  OCI_HTYPE_TRANS, 0, 0);
  OCIAttrSet((void  *)svchp, OCI_HTYPE_SVCCTX, (void  *)txnhp2, 0,
                          OCI_ATTR_TRANS, errhp);

  /* start a transaction with global transaction id = [1000, 123, 2] */
  /* The global transaction is tightly coupled with earlier transactions */
  /* There is not much practical value in doing this but the example */
  /* illustrates the use of tightly coupled transaction branches. */
  /* In a practical case, the second transaction that tightly couples with */
  /* the first can be executed from a different process/thread. */

  gxid.formatID = 1000; /* format id = 1000 */
  gxid.gtrid_length = 3; /* gtrid = 123 */
  gxid.data[0] = 1; gxid.data[1] = 2; gxid.data[2] = 3;
  gxid.bqual_length = 1; /* bqual = 2 */
  gxid.data[3] = 2;

  OCIAttrSet((void  *)txnhp2, OCI_HTYPE_TRANS, (void  *)&gxid,
sizeof(XID), OCI_ATTR_XID, errhp);

  /* start global transaction 2 with 90-second time to live when detached */
  OCITransStart(svchp, errhp, 90, OCI_TRANS_NEW);

  /* update hr.employees employee_id=7902, increment salary */
  /* This is possible even if the earlier transaction has locked this row */
  /* because the two global transactions are tightly coupled */
  OCIStmtExecute(svchp, stmthp, errhp, 1, 0, 0, 0, 0);

  /* detach the transaction */
  OCITransDetach(svchp, errhp, 0);

  /* Resume transaction 1 and prepare it. This returns */
  /* OCI_SUCCESS_WITH_INFO because all branches except the last branch */
  /* are treated as read-only transactions for tightly coupled transactions */

  OCIAttrSet((void  *)svchp, OCI_HTYPE_SVCCTX, (void  *)txnhp1, 0,
                          OCI_ATTR_TRANS, errhp);
  if (OCITransPrepare(svchp, errhp, (ub4) 0) == OCI_SUCCESS_WITH_INFO)
  {
    text errbuf[512];
    ub4 buflen;
    sb4 errcode;

    OCIErrorGet ((void  *) errhp, (ub4) 1, (text *) NULL, &errcode,
    errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR);
    printf("OCITransPrepare - %s\n", errbuf);
  }

  /* attach to transaction 2 and commit it */
  /* set transaction handle2 into the service handle */
  OCIAttrSet((void  *)svchp, OCI_HTYPE_SVCCTX, (void  *)txnhp2, 0,
                          OCI_ATTR_TRANS, errhp);
  OCITransCommit(svchp, errhp, (ub4) 0);
}

関連関数

OCITransDetach()