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. CDatabaseFornece 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 ou Rollback .

  • 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:

  1. Copie o código para CRecordset::Requery( ) para a nova função.

  2. 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 .

Confira também

Notas técnicas por número
Notas técnicas por categoria