TN068. Выполнение транзакций с драйвером Microsoft Access 7 ODBCTN068: Performing Transactions with the Microsoft Access 7 ODBC Driver

Примечание

Следующее техническое примечание не было обновлено, поскольку сначала оно было включено в электронную документацию.The following technical note has not been updated since it was first included in the online documentation. В результате некоторые процедуры и разделы могут быть устаревшими или неверными.As a result, some procedures and topics might be out of date or incorrect. Для получения последних сведений рекомендуется выполнить поиск интересующей темы в алфавитном указателе документации в Интернете.For the latest information, it is recommended that you search for the topic of interest in the online documentation index.

В этом заметке описывается выполнение транзакций при использовании классов базы данных ODBC MFC и драйвера ODBC для Microsoft Access 7,0, входящего в пакет драйверов Microsoft ODBC для рабочих столов версии 3,0.This note describes how to perform transactions when using the MFC ODBC database classes and the Microsoft Access 7.0 ODBC driver included in the Microsoft ODBC Desktop Driver Pack version 3.0.

Общие сведенияOverview

Если приложение базы данных выполняет транзакции, необходимо соблюдать осторожность при вызове CDatabase::BeginTrans и CRecordset::Open в правильной последовательности в приложении.If your database application performs transactions, you must be careful to call CDatabase::BeginTrans and CRecordset::Open in the correct sequence in your application. Драйвер Microsoft Access 7,0 использует ядро СУБД Microsoft Jet, и модуль Jet требует, чтобы приложение не начинало транзакцию в любой базе данных с открытым курсором.The Microsoft Access 7.0 driver uses the Microsoft Jet database engine, and Jet requires that your application not begin a transaction on any database that has an open cursor. Для классов базы данных MFC ODBC открытый курсор эквивалентен открытому CRecordset объекту.For the MFC ODBC database classes, an open cursor equates to an open CRecordset object.

Если набор записей открывается перед вызовом BeginTrans , то могут не отображаться сообщения об ошибках.If you open a recordset before calling BeginTrans, you may not see any error messages. Однако при любом обновлении набора записей приложение становится постоянным после вызова CRecordset::Update , а обновления не будут отменены путем вызова Rollback .However, any recordset updates your application makes become permanent after calling CRecordset::Update, and the updates will not be rolled back by calling Rollback. Чтобы избежать этой проблемы, необходимо сначала вызвать, BeginTrans а затем открыть набор записей.To avoid this problem, you must call BeginTrans first and then open the recordset.

MFC проверяет функциональность драйвера для фиксации и отката курсора.MFC checks the driver functionality for cursor commit and rollback behavior. Класс CDatabase предоставляет две функции члена, GetCursorCommitBehavior и GetCursorRollbackBehavior , чтобы определить воздействие любой транзакции на открытый CRecordset объект.Class CDatabase provides two member functions, GetCursorCommitBehavior and GetCursorRollbackBehavior, to determine the effect of any transaction on your open CRecordset object. Для драйвера ODBC для Microsoft Access 7,0 эти функции-члены возвращают, SQL_CB_CLOSE так как драйвер доступа не поддерживает сохранение курсора.For the Microsoft Access 7.0 ODBC driver, these member functions return SQL_CB_CLOSE because the Access driver does not support cursor preservation. Поэтому необходимо вызвать CRecordset::Requery следующую CommitTrans Rollback операцию или.Therefore, you must call CRecordset::Requery following a CommitTrans or Rollback operation.

Если необходимо выполнить несколько транзакций один за другим, нельзя вызвать Requery после первой транзакции, а затем запустить следующую.When you need to perform multiple transactions one after another, you cannot call Requery after the first transaction and then start the next one. Чтобы удовлетворить требованиям Jet, необходимо закрыть набор записей до следующего вызова в BeginTrans .You must close the recordset before the next call to BeginTrans in order to satisfy Jet's requirement. В этом техническом примечании описаны два метода обработки такой ситуации:This technical note describes two methods of handling this situation:

  • Закрытие набора записей после каждой CommitTrans Rollback операции или.Closing the recordset after each CommitTrans or Rollback operation.

  • Использование функции ODBC API SQLFreeStmt .Using the ODBC API function SQLFreeStmt.

Закрытие набора записей после каждой операции CommitTrans или ROLLBACKClosing the Recordset after each CommitTrans or Rollback Operation

Перед запуском транзакции убедитесь, что объект набора записей закрыт.Before starting a transaction, make sure the recordset object is closed. После вызова BeginTrans вызовите Open функцию члена набора записей.After calling BeginTrans, call the recordset's Open member function. Закройте набор записей сразу после вызова метода CommitTrans или Rollback .Close the recordset immediately after calling CommitTrans or Rollback. Обратите внимание, что многократное открытие и закрытие набора записей может снизить производительность приложения.Note that repeatedly opening and closing the recordset can slow an application's performance.

Использование SQLFreeStmtUsing SQLFreeStmt

Можно также использовать функцию ODBC API SQLFreeStmt для явного закрытия курсора после завершения транзакции.You can also use the ODBC API function SQLFreeStmt to explicitly close the cursor after ending a transaction. Чтобы запустить другую транзакцию, вызовите вызов, BeginTrans за которым следует CRecordset::Requery .To start another transaction, call BeginTrans followed by CRecordset::Requery. При вызове SQLFreeStmt необходимо указать хстмт набора записей в качестве первого параметра и SQL_CLOSE в качестве второго параметра.When calling SQLFreeStmt, you must specify the recordset's HSTMT as the first parameter and SQL_CLOSE as the second parameter. Этот метод выполняется быстрее, чем закрытие и открытие набора записей в начале каждой транзакции.This method is faster than closing and opening the recordset at the start of every transaction. В следующем коде показано, как реализовать этот метод:The following code demonstrates how to implement this technique:

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 которую можно вызвать для запуска следующей транзакции после фиксации или отката первой.Another way to implement this technique is to write a new function, RequeryWithBeginTrans, which you can call to start the next transaction after you commit or rollback the first one. Чтобы написать такую функцию, выполните следующие действия.To write such a function, do the following steps:

  1. Скопируйте код CRecordset::Requery( ) в новую функцию.Copy the code for CRecordset::Requery( ) to the new function.

  2. Добавьте следующую строку сразу после вызова SQLFreeStmt :Add the following line immediately after the call to SQLFreeStmt:

    m_pDatabase->BeginTrans( );

Теперь эту функцию можно вызывать между каждой парой транзакций:Now you can call this function between each pair of transactions:

// 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 между транзакциями.Do not use this technique if you need to change the recordset member variables m_strFilter or m_strSort between transactions. В этом случае необходимо закрыть набор записей после каждой CommitTrans Rollback операции или.In that case, you should close the recordset after each CommitTrans or Rollback operation.

См. также разделSee also

Технические примечания по номеруTechnical Notes by Number
Технические примечания по категориямTechnical Notes by Category