TN068: realizando transações com o driver ODBC do Microsoft Access 7
Observação
A observação técnica a seguir não foi atualizada desde que foi incluída pela primeira vez na documentação online. Como resultado, alguns procedimentos e tópicos podem estar desatualizados ou incorretos. Para obter as informações mais recentes, é recomendável que você pesquise o tópico de interesse no índice de documentação online.
Esta observação descreve como executar transações ao usar as classes de banco de dados ODBC do MFC e o driver ODBC do Microsoft Access 7,0 incluído no Microsoft ODBC Desktop driver Pack versão 3,0.
Visão geral
Se seu aplicativo de banco de dados executa transações, você deve ter cuidado para chamar CDatabase::BeginTrans
e CRecordset::Open
na sequência correta em seu aplicativo. O driver do Microsoft Access 7,0 usa o mecanismo de banco de dados do Microsoft Jet, e o Jet requer que seu aplicativo não inicie uma transação em qualquer banco de dados que tenha um cursor aberto. Para as classes de banco de dados ODBC do MFC, um cursor aberto equivale a um objeto aberto CRecordset
.
Se você abrir um conjunto de registros antes de chamar BeginTrans
, você poderá não ver nenhuma mensagem de erro. No entanto, qualquer conjunto de registros atualiza seu aplicativo torna-se permanente após a chamada CRecordset::Update
, e as atualizações não serão revertidas chamando Rollback
. Para evitar esse problema, você deve chamar BeginTrans
primeiro e, em seguida, abrir o conjunto de registros.
O MFC verifica a funcionalidade do driver para a confirmação do cursor e o comportamento de reversão. CDatabase
Fornece duas funções GetCursorCommitBehavior
de membro e GetCursorRollbackBehavior
, para determinar o efeito de qualquer transação no objeto aberto CRecordset
. Para o driver ODBC do Microsoft Access 7,0, essas funções de membro retornam SQL_CB_CLOSE
porque o driver de acesso não dá suporte à preservação do cursor. Portanto, você deve chamar CRecordset::Requery
a seguir uma CommitTrans
operação ou Rollback
.
Quando você precisar executar várias transações uma após a outra, não poderá chamar Requery
após a primeira transação e, em seguida, iniciar a próxima. Você deve fechar o conjunto de registros antes da próxima chamada para BeginTrans
a fim de satisfazer o requisito do Jet. Esta nota técnica descreve dois métodos para lidar com essa situação:
Fechando o conjunto de registros após cada
CommitTrans
operação ouRollback
.Usando a função
SQLFreeStmt
da API ODBC.
Fechando o conjunto de registros após cada operação CommitTrans ou ROLLBACK
Antes de iniciar uma transação, verifique se o objeto Recordset está fechado. Depois de chamar BeginTrans
, chame a função de membro do Open
conjunto de registros. Feche o conjunto de registros imediatamente após chamar CommitTrans
ou Rollback
. Observe que abrir e fechar repetidamente o conjunto de registros pode reduzir o desempenho de um aplicativo.
Usando SQLFreeStmt
Você também pode usar a função SQLFreeStmt
ODBC API para fechar o cursor explicitamente após encerrar uma transação. Para iniciar outra transação, chame BeginTrans
seguido de CRecordset::Requery
. Ao chamar SQLFreeStmt
, você deve especificar o HSTMT do conjunto de registros como o primeiro parâmetro e SQL_CLOSE como o segundo parâmetro. Esse método é mais rápido do que fechar e abrir o conjunto de registros no início de cada transação. O código a seguir demonstra como implementar essa 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();
Outra maneira de implementar essa técnica é escrever uma nova função, RequeryWithBeginTrans
, que você pode chamar para iniciar a próxima transação depois de confirmar ou reverter a primeira. Para escrever tal função, execute as seguintes etapas:
Copie o código para
CRecordset::Requery( )
para a nova função.Adicione a seguinte linha imediatamente após a chamada para
SQLFreeStmt
:m_pDatabase->BeginTrans( );
Agora você pode chamar essa função entre cada par de transações:
// 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()
Observação
Não use essa técnica se precisar alterar as variáveis de membro do conjunto de registros m_strFilter ou m_strSort entre as transações. Nesse caso, você deve fechar o conjunto de registros após cada CommitTrans
operação ou Rollback
.