TN068: Realizar transacciones con el controlador ODBC de Microsoft Access 7
Nota:
La nota técnica siguiente no se ha actualizado desde que se incluyó por primera vez en la documentación en línea. Como resultado, algunos procedimientos y temas podrían estar obsoletos o ser incorrectos. Para obtener información más reciente, se recomienda buscar el tema de interés en el índice de la documentación en línea.
En esta nota se describe cómo realizar transacciones al usar las clases de base de datos de ODBC de MFC y el controlador ODBC de Microsoft Access 7.0 incluido en el paquete de controladores para Microsoft ODBC Desktop versión 3.0.
Información general
Si la aplicación de base de datos realiza transacciones, debe tener cuidado de llamar a CDatabase::BeginTrans
y CRecordset::Open
en la secuencia correcta de la aplicación. El controlador de Microsoft Access 7.0 usa el motor de base de datos de Microsoft Jet y Jet requiere que la aplicación no inicie una transacción en ninguna base de datos que tenga un cursor abierto. Para las clases de base de datos ODBC de MFC, un cursor abierto equivale a un objeto CRecordset
abierto.
Si abre un conjunto de registros antes de llamar a BeginTrans
, es posible que no vea ningún mensaje de error. Sin embargo, las actualizaciones del conjunto de registros que la aplicación realiza se convierten en permanentes después de llamar a CRecordset::Update
y las actualizaciones no se revertirán al llamar a Rollback
. Para evitar este problema, primero debe llamar a BeginTrans
y, a continuación, abrir el conjunto de registros.
MFC comprueba la funcionalidad del controlador para comprobar el comportamiento de reversión y confirmación del cursor. La clase CDatabase
proporciona dos funciones miembro, GetCursorCommitBehavior
y GetCursorRollbackBehavior
, para determinar el efecto de cualquier transacción en el objeto CRecordset
abierto. Para el controlador ODBC de Microsoft Access 7.0, estas funciones miembro devuelven SQL_CB_CLOSE
porque el controlador de Access no admite la conservación del cursor. Por lo tanto, debe llamar a CRecordset::Requery
después de una operación CommitTrans
o Rollback
.
Cuando necesite realizar varias transacciones una después de otra, no puede llamar a Requery
después de la primera transacción y, a continuación, iniciar la siguiente. Debe cerrar el conjunto de registros antes de la siguiente llamada a BeginTrans
para satisfacer los requisitos de Jet. Esta nota técnica describe dos métodos para controlar esta situación:
Cerrar el conjunto de registros después de cada operación
CommitTrans
oRollback
.Usar la función de API de ODBC
SQLFreeStmt
.
Cierre del conjunto de registros después de cada operación CommitTrans o Rollback
Antes de iniciar una transacción, asegúrese de que el objeto del conjunto de registros está cerrado. Después de llamar a BeginTrans
, llame a la función miembro Open
del conjunto de registros. Cierre el conjunto de registros inmediatamente después de llamar a CommitTrans
o Rollback
. Tenga en cuenta que abrir y cerrar repetidamente el conjunto de registros puede ralentizar el rendimiento de una aplicación.
Uso de SQLFreeStmt
También puede usar la función SQLFreeStmt
de la API de ODBC para cerrar explícitamente el cursor después de finalizar una transacción. Para iniciar otra transacción, llame a BeginTrans
seguida de CRecordset::Requery
. Al llamar a SQLFreeStmt
, debe especificar el HSTMT del conjunto de registros como primer parámetro y SQL_CLOSE como segundo parámetro. Este método es más rápido que cerrar y abrir el conjunto de registros al principio de cada transacción. El siguiente código muestra cómo implementar esta técnica:
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();
Otra manera de implementar esta técnica es escribir una nueva función, RequeryWithBeginTrans
, a la que puede llamar para iniciar la siguiente transacción después de confirmar o revertir la primera. Para escribir esta función, siga estos pasos:
Copie el código para
CRecordset::Requery( )
en la nueva función.Agregue la siguiente línea inmediatamente después de la llamada a
SQLFreeStmt
:m_pDatabase->BeginTrans( );
Ahora puede llamar a esta función entre cada par de transacciones:
// 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()
Nota:
No use esta técnica si necesita cambiar las variables miembro del conjunto de registros m_strFilter o m_strSort entre transacciones. En ese caso, debe cerrar el conjunto de registros después de cada operaciónCommitTrans
o Rollback
.