注
次のテクニカル ノートは、最初にオンライン ドキュメントに含まれてから更新されていません。 その結果、一部の手順やトピックが古くなっているか、正しくない可能性があります。 最新情報については、オンライン ドキュメント インデックスで関心のあるトピックを検索することをお勧めします。
このノートでは、MFC ODBC データベース クラスと、Microsoft ODBC デスクトップ ドライバー パック バージョン 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
には、 GetCursorCommitBehavior
と GetCursorRollbackBehavior
の 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
) を記述することです。この関数は、最初のトランザクションをコミットまたはロールバックした後で次のトランザクションを開始するために呼び出すことができます。 このような関数を記述するには、次の手順を実行します。
CRecordset::Requery( )
のコードを新しい関数にコピーします。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
操作の後にレコードセットを閉じる必要があります。