この項では、トランザクション関数について説明します。
表17-10 トランザクション関数
| 関数 | 用途 |
|---|---|
|
|
サービス・コンテキスト上のトランザクションをコミットします。 |
|
|
サービス・コンテキストからトランザクションを連結解除します。 |
|
|
準備したグローバル・トランザクションを放棄します。 |
|
|
単一セルに複数のブランチがあるトランザクションを準備します。 |
|
|
グローバル・トランザクションをコミットのために準備します。 |
|
|
トランザクションをロールバックします。 |
|
|
サービス・コンテキスト上のトランザクションを開始します。 |
用途
指定のサービス・コンテキストに対応付けられたトランザクションをコミットします。
構文
sword OCITransCommit ( OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags );
パラメータ
サービス・コンテキスト・ハンドルです。
エラー発生時の診断情報のためにOCIErrorGet()に渡すエラー・ハンドルです。
グローバル・トランザクションの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を開始することを示します。BATCHとIMMEDIATEの両方を指定するとエラーが発生します。デフォルトはIMMEDIATEです。
OCI_TRANS_WRITEWAIT− これは、コミットのREDOバッファをオンラインREDOログに書き込むようLGWRに要求し、書き込まれるまではコミットを待機させます。WAITとは、トランザクションに対応するメモリー内REDOバッファが永続オンラインREDOログに書き込まれて初めてコミットが終了することを示します。
OCI_TRANS_WRITENOWAIT− これは、コミットのREDOバッファをオンラインREDOログに書き込むようLGWRに要求しますが、バッファがオンラインREDOログに書き込まれるのを待たずにコミットは終了します。NOWAITとは、メモリー内REDOバッファをオンラインREDOログにフラッシュせずにコミットが終了することを示します。WAITとNOWAITの両方を指定するとエラーが発生します。デフォルトはWAITです。
|
注意: OCI_TRANS_WRITENOWAITを使用すると、警告なしでトランザクションが消失する可能性があります。トランザクションの消失は、強制停止、強制起動、およびインスタンス障害やノード障害によって、警告なしに発生します。RACシステムでは、非同期にコミットされた場合、他のインスタンスでその変更を即時に読み取れない場合があります。 |
これら最後の4つのオプションは、分散型でないトップレベルのトランザクションのコミットのみに影響し、外部協調分散トランザクションでは無視されます。これらのオプションは、指定されている制限内容に応じてOR演算子を使用して結合できます。
コメント
サービス・コンテキストに現在対応付けられているトランザクションをコミットします。トランザクションがサーバーによるコミットが不可能なグローバル・トランザクションである場合、このコールは、トランザクションの状態をデータベースから取り出し、エラー・ハンドルを使用してユーザーに戻します。
複数のトランザクションを定義している場合、この関数は、サービス・コンテキストに現在対応付けられているトランザクションを処理します。データベースの変更時に作成される暗黙的ローカル・トランザクションのみを処理している場合は、その暗黙的トランザクションがコミットされます。
アプリケーションをオブジェクト・モードで実行している場合は、このトランザクションに対してオブジェクト・キャッシュで変更または更新されたオブジェクトもフラッシュされ、コミットされます。
正常な状況では、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);
}
関連関数
用途
トランザクションの連結を解除します。
構文
sword OCITransDetach ( OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags );
パラメータ
サービス・コンテキスト・ハンドルです。
エラー発生時の診断情報のためにOCIErrorGet()に渡すエラー・ハンドルです。
このパラメータ用に値OCI_DEFAULTを渡す必要があります。
コメント
サービス・コンテキスト・ハンドルからグローバル・トランザクションを連結解除します。このコールが終了した時点で、サービス・コンテキスト・ハンドルに現在連結されているトランザクションが非活動状態になります。このトランザクションは、後でOCITransStart()をコールしながらOCI_TRANS_RESUMEのフラグ値を指定するときに再開できます。
トランザクションの連結が解除されると、トランザクションの開始時にOCITransStart()のタイムアウト・パラメータに指定された値を使用して、サーバーのPMONプロセスによって削除されるまでブランチを非活動状態にしておける時間が判断されます。
|
注意: トランザクションが同一の認可を持っている場合、トランザクションはその連結を解除したプロセス以外のプロセスによっても再開できます。トランザクションが実際に開始される前にこの関数がコールされると、この関数は何も行いません。 |
OCITransDetach()の使用方法を説明するコード例については、OCITransStart()の説明を参照してください。
関連関数
用途
完了したグローバル・トランザクションをサーバーに放棄させます。
構文
sword OCITransForget ( OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags );
パラメータ
トランザクションが常駐するサービス・コンテキスト・ハンドルです。
エラー発生時の診断情報のためにOCIErrorGet()に渡すエラー・ハンドルです。
このパラメータ用にOCI_DEFAULTを渡す必要があります。
コメント
完了したグローバル・トランザクションを放棄します。サーバーにより、システムのペンディング・トランザクション表からトランザクションの状態が削除されます。
放棄されるトランザクションのXIDをトランザクション・ハンドルの属性として設定します(OCI_ATTR_XID)。
関連関数
OCITransCommit()、OCITransRollback()
用途
単一セルに複数のブランチがあるトランザクションを準備します。
構文
sword OCITransMultiPrepare ( OCISvcCtx *svchp,
ub4 numBranches,
OCITrans **txns,
OCIError **errhp);
パラメータ
サービス・コンテキスト・ハンドルです。
ブランチの数を指定します。この値は、次の2つのパラメータの配列サイズでもあります。
準備するブランチのトランザクション・ハンドルの配列です。これらにはすべてOCI_ATTR_XIDが設定されます。グローバル・トランザクションIDは同じにしてください。
エラー・ハンドルの配列です。OCI_SUCCESSが戻されない場合、このパラメータによってどのブランチがどのエラーを受信したか示されます。
コメント
指定のグローバル・トランザクションをコミットできるように準備します。このコールは、分散トランザクションに対してのみ有効です。このコールは、コール元がトランザクションですべてのブランチを準備する場合にかぎり使用する拡張パフォーマンス機能です。
関連関数
用途
トランザクションをコミットできるように準備します。
構文
sword OCITransPrepare ( OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags );
パラメータ
サービス・コンテキスト・ハンドルです。
エラー発生時の診断情報のためにOCIErrorGet()に渡すエラー・ハンドルです。
このパラメータ用にOCI_DEFAULTを渡す必要があります。
コメント
指定のグローバル・トランザクションをコミットできるように準備します。
このコールは、グローバル・トランザクションに対してのみ有効です。
このコールは、トランザクションが変更されていない場合はOCI_SUCCESS_WITH_INFOを戻します。エラー・ハンドルは、トランザクションが読取り専用であることを示します。flagsパラメータは、現在使用されていません。
関連関数
OCITransCommit()、OCITransForget()
用途
カレント・トランザクションをロールバックします。
構文
sword OCITransRollback ( void *svchp,
OCIError *errhp,
ub4 flags );
パラメータ
サービス・コンテキスト・ハンドルです。サービス・コンテキスト・ハンドル内に現在設定されているトランザクションがロールバックされます。
エラー発生時の診断情報のためにOCIErrorGet()に渡すエラー・ハンドルです。
このパラメータ用に値OCI_DEFAULTを渡す必要があります。
コメント
カレント・トランザクション(最後のOCITransCommit()、またはOCISessionBegin()以降に実行された一連の文として定義されます)がロールバックされます。
アプリケーションがオブジェクト・モードで実行されている場合は、このトランザクションで修正または更新されたオブジェクト・キャッシュ内のオブジェクトも同様にロールバックされます。
現在アクティブでないグローバル・トランザクションをロールバックしようとすると、エラーになります。
例
OCITransRollback()の使用方法を説明するコード例については、OCITransCommit()の説明を参照してください。
関連関数
用途
トランザクションの開始を設定します。
構文
sword OCITransStart ( OCISvcCtx *svchp,
OCIError *errhp,
uword timeout,
ub4 flags );
パラメータ
サービス・コンテキスト・ハンドルです。flagsパラメータに新規トランザクションの開始が指定されている場合は、このコールの終了時点で、サービス・コンテキスト・ハンドル内のトランザクション・コンテキストが初期化されます。
OCIエラー・ハンドルです。エラーがある場合は、errに記録され、OCI_ERRORが戻されます。OCIErrorGet()のコールによって診断情報を取得できます。
OCI_TRANS_RESUMEが指定されたときに、トランザクションが再開できるようになるまで待機する時間(秒)です。OCI_TRANS_NEWが指定されると、timeoutパラメータの指示する秒数間、非活動状態が続いたトランザクションは、システムによって自動的に終了します。トランザクションは、OCITransDetach()による連結解除から、OCITransStart()による再開までの間、非活動状態になります。
新規トランザクションが開始中か、または既存のトランザクションが再開中であるかを指定します。シリアライズ可能または読取り専用ステータスも指定します。複数の値を指定できます。デフォルトでは、読取りトランザクションまたは書込みトランザクションが開始されます。フラグ値は次のとおりです。
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「複数のブランチで動作するセッション」を参照してください。
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);
}
例2− 同一のトランザクションを共有する複数のブランチ上で動作するシングル・セッション
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 will be tightly coupled with earlier transaction */
/* 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 will return */
/* 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);
}
関連関数