TN068: esecuzione di transazioni con il driver ODBC di Microsoft Access 7
Nota
La seguente nota tecnica non è stata aggiornata da quando è stata inclusa per la prima volta nella documentazione online. Di conseguenza, alcune procedure e argomenti potrebbero essere non aggiornati o errati. Per le informazioni più recenti, è consigliabile cercare l'argomento di interesse nell'indice della documentazione online.
Questa nota descrive come eseguire transazioni quando si usano le classi di database ODBC MFC e il driver ODBC di Microsoft Access 7.0 incluso in Microsoft ODBC Desktop Driver Pack versione 3.0.
Panoramica
Se l'applicazione di database esegue transazioni, è necessario prestare attenzione a chiamare CDatabase::BeginTrans
e CRecordset::Open
nella sequenza corretta nell'applicazione. Il driver di Microsoft Access 7.0 usa il motore di database Microsoft Jet e Jet richiede che l'applicazione non inizi una transazione su qualsiasi database con un cursore aperto. Per le classi di database ODBC MFC, un cursore aperto equivale a un oggetto aperto CRecordset
.
Se si apre un recordset prima di chiamare BeginTrans
, è possibile che non vengano visualizzati messaggi di errore. Tuttavia, tutti gli aggiornamenti del recordset apportati dall'applicazione diventano permanenti dopo la chiamata CRecordset::Update
a e non verrà eseguito il rollback degli aggiornamenti chiamando Rollback
. Per evitare questo problema, è necessario chiamare BeginTrans
prima e quindi aprire il recordset.
MFC controlla la funzionalità del driver per il commit del cursore e il comportamento di rollback. La classe CDatabase
fornisce due funzioni membro e GetCursorRollbackBehavior
GetCursorCommitBehavior
, per determinare l'effetto di qualsiasi transazione sull'oggetto apertoCRecordset
. Per il driver ODBC di Microsoft Access 7.0, queste funzioni membro restituiscono SQL_CB_CLOSE
perché il driver di Access non supporta la conservazione dei cursori. Pertanto, è necessario chiamare CRecordset::Requery
dopo un'operazione CommitTrans
o Rollback
.
Quando è necessario eseguire più transazioni una dopo l'altra, non è possibile chiamare Requery
dopo la prima transazione e quindi avviare quella successiva. È necessario chiudere il recordset prima della chiamata successiva a BeginTrans
per soddisfare i requisiti di Jet. Questa nota tecnica descrive due metodi di gestione di questa situazione:
Chiusura del recordset dopo ogni
CommitTrans
operazione oRollback
.Uso della funzione
SQLFreeStmt
API ODBC .
Chiusura dell'oggetto Recordset dopo ogni operazione committrans o rollback
Prima di avviare una transazione, assicurarsi che l'oggetto recordset sia chiuso. Dopo aver chiamato , chiamare BeginTrans
la funzione membro del Open
recordset. Chiudere il recordset immediatamente dopo aver chiamato CommitTrans
o Rollback
. Si noti che l'apertura e la chiusura ripetute del recordset possono rallentare le prestazioni di un'applicazione.
Uso di SQLFreeStmt
È anche possibile usare la funzione SQLFreeStmt
API ODBC per chiudere in modo esplicito il cursore dopo aver terminato una transazione. Per avviare un'altra transazione, chiamare BeginTrans
seguito da CRecordset::Requery
. Quando si chiama SQLFreeStmt
, è necessario specificare HSTMT del recordset come primo parametro e SQL_CLOedizione Standard come secondo parametro. Questo metodo è più veloce rispetto alla chiusura e all'apertura del recordset all'inizio di ogni transazione. Il codice seguente illustra come implementare questa tecnica:
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();
Un altro modo per implementare questa tecnica consiste nel scrivere una nuova funzione, RequeryWithBeginTrans
, che è possibile chiamare per avviare la transazione successiva dopo il commit o il rollback della prima. Per scrivere una funzione di questo tipo, seguire questa procedura:
Copiare il codice per
CRecordset::Requery( )
nella nuova funzione.Aggiungere la riga seguente subito dopo la chiamata a
SQLFreeStmt
:m_pDatabase->BeginTrans( );
È ora possibile chiamare questa funzione tra ogni coppia di transazioni:
// 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
Non usare questa tecnica se è necessario modificare le variabili membro del recordset m_strFilter o m_strSort tra transazioni. In tal caso, è necessario chiudere il recordset dopo ogni CommitTrans
operazione o Rollback
.