TN068: realizando transações com o driver ODBC do Microsoft Access 7

Observação

A nota 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 nota 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 o seu aplicativo de banco de dados executar transações, você deverá ter cuidado ao 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 exige que o seu aplicativo não inicie uma transação em qualquer banco de dados que tenha cursor aberto. Para as classes de banco de dados ODBC do MFC, um cursor aberto equivale a um objetoCRecordset aberto.

Se você abrir um conjunto de registros antes de chamar BeginTrans, talvez não veja nenhuma mensagem de erro. No entanto, qualquer atualização de conjunto de registros que seu aplicativo fizer se torna permanente após chamar CRecordset::Update, e as atualizações não serão revertidas chamando Rollback. Para evitar esse problema, você deve chamar BeginTrans primeiro e só depois abrir o conjunto de registros.

O MFC verifica a funcionalidade do driver quanto ao comportamento para fazer commit e reverter o cursor. A classe CDatabase fornece duas funções membro, GetCursorCommitBehavior e GetCursorRollbackBehavior, para determinar o efeito de qualquer transação em seu objeto CRecordset aberto. Para o driver ODBC do Microsoft Access 7.0, essas funções de membro retornam SQL_CB_CLOSE porque o driver do Access não dá suporte à preservação do cursor. Por conta disso, você precisa chamar CRecordset::Requery após uma operação CommitTrans ou Rollback.

Quando você precisa executar várias transações uma após a outra, não é possível 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 para atender aos requisitos do Jet. Esta nota técnica descreve dois métodos para lidar com essa situação:

  • Fechar o conjunto de registros após cada operação CommitTrans ou Rollback.

  • Usar a função de API ODBC SQLFreeStmt.

Fechar o conjunto de registros após cada operação CommitTrans ou Rollback

Antes de iniciar uma transação, verifique se o objeto do conjunto de registros está fechado. Depois de chamar BeginTrans, chame a função membro Open do conjunto de registros. Feche o conjunto de registros imediatamente após chamar CommitTrans ou Rollback. Observe que abrir e fechar o conjunto de registros repetidamente pode diminuir o desempenho de um aplicativo.

Usar SQLFreeStmt

Você também pode usar a função de API ODBC SQLFreeStmt para fechar explicitamente o cursor depois de encerrar uma transação. Para iniciar outra transação, chame BeginTrans seguido por 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 exemplo de 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 essa função, siga estas etapas:

  1. Copie o código de 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 transações. Nesse caso, você deve fechar o conjunto de registros após cada operação CommitTrans ou Rollback.

Confira também

Observações técnicas por número
Observações técnicas por categoria