TN068. Выполнение транзакций с драйвером Microsoft Access 7 ODBC

Примечание.

Следующее техническое примечание не было обновлено, поскольку сначала оно было включено в электронную документацию. В результате некоторые процедуры и разделы могут быть устаревшими или неверными. Для получения последних сведений рекомендуется выполнить поиск интересующей темы в алфавитном указателе документации в Интернете.

В этой заметке описывается, как выполнять транзакции при использовании классов базы данных ODBC MFC и драйвера ODBC Microsoft Access 7.0, включенного в пакет драйверов для настольных компьютеров Microsoft ODBC версии 3.0.

Обзор

Если приложение базы данных выполняет транзакции, необходимо внимательно вызывать CDatabase::BeginTrans и CRecordset::Open в правильной последовательности в приложении. Драйвер Microsoft Access 7.0 использует ядро СУБД Microsoft Jet и Jet требует, чтобы приложение не начало транзакции в любой базе данных с открытым курсором. Для классов баз данных ODBC MFC открытый курсор приравнивается к открытому CRecordset объекту.

Если вы открываете набор записей перед вызовом BeginTrans, сообщения об ошибках не отображаются. Однако любой набор записей обновляет приложение становится постоянным после вызова CRecordset::Update, и обновления не будут откатированы путем вызова Rollback. Чтобы избежать этой проблемы, необходимо сначала вызвать BeginTrans и открыть набор записей.

MFC проверка функциональные возможности драйвера для поведения фиксации и отката курсора. Класс CDatabase предоставляет две функции-члены и GetCursorCommitBehaviorGetCursorRollbackBehaviorопределяет влияние любой транзакции на открытый CRecordset объект. Для драйвера ODBC Microsoft Access 7.0 эти функции-члены возвращаются SQL_CB_CLOSE , так как драйвер Access не поддерживает сохранение курсоров. Таким образом, необходимо вызвать CRecordset::Requery следующую CommitTrans или Rollback операцию.

Когда необходимо выполнить несколько транзакций друг за другом, вы не можете вызвать Requery после первой транзакции, а затем запустить следующую. Перед следующим вызовом BeginTrans необходимо закрыть набор записей, чтобы удовлетворить требования Jet. В этой технической записке описаны два способа обработки этой ситуации:

  • Закрытие набора записей после каждой CommitTrans операции или Rollback операции.

  • Использование функции SQLFreeStmtAPI ODBC.

Закрытие набора записей после каждой операции CommitTrans или rollback

Перед началом транзакции убедитесь, что объект набора записей закрыт. После вызова вызовите BeginTransфункцию-член набора Open записей. Закройте набор записей сразу после вызова CommitTrans или Rollback. Обратите внимание, что многократное открытие и закрытие набора записей может замедлить производительность приложения.

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

Вы также можете использовать функцию SQLFreeStmt API ODBC для явного закрытия курсора после завершения транзакции. Чтобы запустить другую транзакцию, выполните вызов BeginTrans , за которым следует CRecordset::Requery. При вызове SQLFreeStmtнеобходимо указать HSTMT набора записей в качестве первого параметра и 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 операции.

См. также

Технические примечания по номеру
Технические примечания по категории