次の方法で共有


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

注意

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

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

概要

作成するデータベース アプリケーションでトランザクションを実行する場合には、アプリケーションの適切なシーケンスから CDatabase::BeginTrans および CRecordset::Open を呼び出すように注意する必要があります。 Microsoft Access 7.0 ドライバーでは Microsoft Jet データベース エンジンを使用しますが、このエンジンは開かれたカーソルがある状態のデータベースとアプリケーションとの間のトランザクションの開始をサポートしていません。 MFC ODBC データベース クラスでは、CRecordset オブジェクトが開かれている状態が、カーソルが開いた状態に当たります。

BeginTrans の呼び出し前にレコードセットを開いても、特にエラー メッセージは表示されません。 ただし、アプリケーションによって行われたレコードセットの更新は CRecordset::Update の呼び出し後に確定され、この更新内容は Rollback を呼び出してもロールバックできません。 このような問題が発生しないように、あらかじめ BeginTrans を呼び出してからレコードセットを開く必要があります。

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

複数のトランザクション処理を連続的に行う場合は、先行するトランザクション処理後の Requery の呼び出しによって次のトランザクションを開始することはできません。 Jet の要件を満たすには、BeginTrans を再度呼び出す前にレコードセットを閉じる必要があります。 このような状況を処理するための 2 とおりの処理方法を説明します。

  • CommitTrans または Rollback 処理の後にレコードセットを閉じる

  • ODBC API 関数 SQLFreeStmt を使用する

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

トランザクションを開始する前に、レコードセット オブジェクトを閉じておく必要があります。 BeginTrans の呼び出し後に、処理対象のレコードセットのメンバー関数 Open の呼び出しによってレコードセットを開きます。 CommitTrans または Rollback を呼び出した後には、すぐにレコードセットを閉じます。 同じレコードセットを繰り返し開閉すると、アプリケーションの動作が遅くなることがあるため注意が必要です。

SQLFreeStmt の使用

ODBC API 関数 SQLFreeStmt を使用して、トランザクション後に明示的にカーソルを閉じることもできます。 他のトランザクションを開始するには、BeginTrans を呼び出し、続けて CRecordset::Requery を呼び出します。 SQLFreeStmt の呼び出しには、第 1 パラメーターとしてレコードセットの 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( );

先行するトランザクションをコミットまたはロールバックした後で次のトランザクションを開始する関数 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 処理の後にレコードセットを閉じる必要があります。

参照

その他の技術情報

番号順テクニカル ノート

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