次の方法で共有


TN068: Microsoft Access 7 ODBC ドライバーを使用したトランザクションの実行

次のテクニカル ノートは、最初にオンライン ドキュメントに含まれてから更新されていません。 その結果、一部の手順やトピックが古くなっているか、正しくない可能性があります。 最新情報については、オンライン ドキュメント インデックスで関心のあるトピックを検索することをお勧めします。

このノートでは、MFC ODBC データベース クラスと、Microsoft ODBC デスクトップ ドライバー パック バージョン 3.0 に含まれる Microsoft Access 7.0 ODBC ドライバーを使用するときにトランザクションを実行する方法について説明します。

概要

データベース アプリケーションがトランザクションを実行する場合は、アプリケーションで適切な順序で CDatabase::BeginTransCRecordset::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 を返します。 したがって、CRecordset::RequeryまたはCommitTrans操作の後にRollbackを呼び出す必要があります。

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

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

  • ODBC API 関数を使用 SQLFreeStmt

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

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

SQLFreeStmt の使用

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

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()

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

こちらも参照ください

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