Share via


テクニカル ノート 68: Microsoft Access 7 ODBC ドライバーでのトランザクションの実行

Note

次のテクニカル ノートは、最初にオンライン ドキュメントの一部とされてから更新されていません。 結果として、一部のプロシージャおよびトピックが最新でないか、不正になります。 最新の情報について、オンライン ドキュメントのキーワードで関係のあるトピックを検索することをお勧めします。

このテクニカル ノートでは、MFC ODBC データベース クラスおよび Microsoft ODBC Desktop Driver Pack バージョン3.0 に含まれている Microsoft Access 7.0 ODBC ドライバーを使用する場合のトランザクションの実行方法について説明します。

概要

データベース アプリケーションでトランザクションを実行する場合は、アプリケーションで正しい順序で CDatabase::BeginTrans および CRecordset::Open を呼び出すように注意する必要があります。 Microsoft Access 7.0 ドライバーは Microsoft Jet データベース エンジンを使用します。Jet は、アプリケーションに、開いているカーソルがあるデータベースでトランザクションを開始しないように要求します。 MFC ODBC データベース クラスでは、開いているカーソルは開いている CRecordset オブジェクトに相当します。

BeginTrans を呼び出す前にレコードセットを開くと、エラー メッセージが表示されない場合があります。 ただし、CRecordset::Update を呼び出した後に、アプリケーションが行うレコードセットの更新は永続的になり、更新プログラムは Rollback を呼び出すことによってロール バックされません。 この問題を回避するには、まず BeginTrans を呼び出し、次にレコードセットを開く必要があります。

MFC は、カーソルのコミットとロールバックの動作について、ドライバーの機能を確認します。 クラス CDatabase には、GetCursorCommitBehaviorGetCursorRollbackBehavior の 2 つのメンバー関数が用意されており、開いている CRecordset オブジェクトに対するトランザクションの影響を判定します。 Microsoft Access 7.0 ODBC ドライバーでは、Access ドライバーはカーソルの保持をサポートしていないため、これらのメンバー関数は SQL_CB_CLOSE を返します。 したがって、CommitTrans または Rollback の操作の後に CRecordset::Requery を呼び出す必要があります。

複数のトランザクションを 1 つずつ実行する必要がある場合、最初のトランザクションの後に Requery を呼び出して、次のトランザクションを開始することはできません。 Jet の要件を満たすために、次の BeginTrans への呼び出しの前にレコードセットを閉じる必要があります。 このテクニカル ノートでは、この状況を処理する 2 つの方法について説明します。

  • CommitTrans または Rollback の各操作の後にレコードセットを閉じます。

  • ODBC API 関数 SQLFreeStmt を使用します。

各 CommitTrans または Rollback 操作の後にレコードセットを閉じる

トランザクションを開始する前に、レコードセット オブジェクトが閉じていることを確認します。 BeginTrans を呼び出した後、レコードセットの Open メンバー関数を呼び出します。 CommitTrans または Rollback を呼び出した直後に、レコードセットを閉じます。 レコードセットを繰り返し開いたり閉じたりすると、アプリケーションのパフォーマンスが低下する可能性があることに注意してください。

SQLFreeStmt の使用

また、ODBC API 関数 SQLFreeStmt を使用して、トランザクションの終了後にカーソルを明示的に閉じることもできます。 別のトランザクションを開始するには、BeginTrans を呼び出した後に CRecordset::Requery を呼び出します。 SQLFreeStmt を呼び出すときは、レコードセットの HSTMT を最初のパラメーターとして指定し、SQL_CLOSE を 2 番目のパラメーターとして指定する必要があります。 このメソッドは、トランザクションの開始時ごとにレコードセットを閉じて開くよりも高速です。 この手法を実装する方法を次のコード例に示します。

CMyDatabase db;
db.Open("MYDATASOURCE");
CMyRecordset rs(&db);

// start transaction 1 and
// open the recordset
db.BeginTrans();
rs.Open();

// manipulate data

// end transaction 1
db.CommitTrans(); // or Rollback()

// close the cursor
::SQLFreeStmt(rs.m_hstmt, SQL_CLOSE);

// start transaction 2
db.BeginTrans();
// now get the result set
rs.Requery();

// manipulate data

// end transaction 2
db.CommitTrans();

rs.Close();
db.Close();

この手法を実装するもう 1 つの方法は、新しい関数 RequeryWithBeginTrans を記述することです。これを呼び出すと、最初のトランザクションをコミットまたはロールバックした後に、次のトランザクションを開始できます。 このような関数を記述するには、次の手順を実行します。

  1. CRecordset::Requery( ) のコードを新しい関数にコピーします。

  2. SQLFreeStmt の呼び出しの直後に、次の行を追加します。

    m_pDatabase->BeginTrans( );

これで、この関数をトランザクションの各ペア間で呼び出せるようになりました。

// start transaction 1 and
// open the recordset
db.BeginTrans();

rs.Open();

// manipulate data

// end transaction 1
db.CommitTrans();   // or Rollback()

// close the cursor, start new transaction,
// and get the result set
rs.RequeryWithBeginTrans();

// manipulate data

// end transaction 2
db.CommitTrans();   // or Rollback()

Note

トランザクション間でレコードセット メンバー変数 m_strFilter または m_strSort を変更する必要がある場合は、この手法を使用しないでください。 その場合は、CommitTrans または Rollback 操作の後にレコードセットを閉じる必要があります。

関連項目

番号順テクニカル ノート
カテゴリ別テクニカル ノート