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
предоставляет две функции-члены и GetCursorCommitBehavior
GetCursorRollbackBehavior
определяет влияние любой транзакции на открытый CRecordset
объект. Для драйвера ODBC Microsoft Access 7.0 эти функции-члены возвращаются SQL_CB_CLOSE
, так как драйвер Access не поддерживает сохранение курсоров. Таким образом, необходимо вызвать CRecordset::Requery
следующую CommitTrans
или Rollback
операцию.
Когда необходимо выполнить несколько транзакций друг за другом, вы не можете вызвать Requery
после первой транзакции, а затем запустить следующую. Перед следующим вызовом BeginTrans
необходимо закрыть набор записей, чтобы удовлетворить требования Jet. В этой технической записке описаны два способа обработки этой ситуации:
Закрытие набора записей после каждой
CommitTrans
операции илиRollback
операции.Использование функции
SQLFreeStmt
API 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
которую можно вызвать для запуска следующей транзакции после фиксации или отката первой. Чтобы написать такую функцию, сделайте следующее:
Скопируйте код для
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
операции.
См. также
Технические примечания по номеру
Технические примечания по категории