DAO Workspace: Managing Transactions

HomeOverviewHow Do IFAQSampleTutorialODBC Driver List

This article explains the MFC facilities available for managing transactions and refers you to additional information in DAO Help. For general transaction information in DAO, see the topic "BeginTrans, CommitTrans, Rollback Methods" in DAO Help.

Topics covered include:

Transaction: Defined

A transaction is a series of changes made to a database's data and/or schema. Mark the beginning of a transaction by calling the BeginTrans member function of class CDaoWorkspace. Commit the transaction using the CommitTrans member function, or undo all your changes since BeginTrans using the Rollback member function.

The key idea of transactions is that the operation is “atomic” — a group of related smaller operations must all succeed for the whole operation to succeed. If one small operation fails, the whole operation fails.

There is an implicit transaction while action queries are running. If a query doesn't complete for any reason, it is automatically rolled back. Transactions are optional and can be nested up to five levels. (This is in contrast to ODBC, which does not permit nested transactions.) Transactions increase the speed of data changing operations and enable changes to be reversed easily.

The current transaction consists of all changes made to a recordset object after you last called the BeginTrans member function and before you call the Rollback or CommitTrans member functions.

Transaction Spaces

The workspace object defines a transaction space. Transactions are global to the workspace in which they occur. They affect all open databases, recordsets, and querydefs in the same workspace. If you have several open recordsets and/or databases in a workspace, each call to BeginTrans, CommitTrans, and Rollback applies to all of the objects.

For example, suppose you have called BeginTrans for a workspace and you begin updates through two recordsets that belong to database objects in the same workspace. If you call CommitTrans or RollBack in the workspace, the call affects both recordsets, even if they are open on different databases.

If this transaction model is not what you need, you can open separate transaction spaces by opening separate workspaces. Create a new CDaoWorkspace object for each separate transaction space. For more information, see the article DAO Workspace: Opening a Separate Transaction Space.

Transaction Example

The following example illustrates transactions by using two recordsets to delete a student's enrollment from a school registration database. First it removes the student from all classes in which the student is enrolled. Then it removes the student's master record, after which the student no longer exists in the database.

The Delete calls in both recordsets must succeed, so a transaction is required.

Important   The example shown illustrates correct transaction procedure, but for the illustrated case this is not the most efficient way to do the job. For details, see the discussion in Efficiency Considerations for This Example.

The example assumes the existence of:

The example modifies the default SQL string defined with ClassWizard before opening the recordset. The modification filters the records with a student ID passed in as a parameter.

BOOL CEnrollDoc::RemoveStudent(CString strStudentID)
{
    // Construct a recordset for courses student is in
    CEnrollmentSet rsEnrollmentSet( &m_dbStudentReg );

    // Define the SQL string for the recordset to 
    // Filter records with the SQL keyword WHERE
    CString strSQL = rsEnrollmentSet.GetDefautlSQL( ) + 
                "WHERE [Student ID] = " + strStudentID;
    try
    {
        // Open the recordset using 
        // the modified SQL string
        rsEnrollmentSet.Open( dbOpenDynaset, strSQL );

        // Start the transaction
        m_dbStudentReg.m_pWorkspace->BeginTrans( );

        // Remove the student from all classes the 
        // student is enrolled in
        while ( !rsEnrollmentSet.IsEOF( ) )
        {
            rsEnrollmentSet.Delete( );
            rsEnrollmentSet.MoveNext( );
        }
        // Delete the student's master record
        m_rsStudentSet.Delete( );

       // Commit the transaction
       m_dbStudentReg.m_pWorkspace->CommitTrans( );
    }
    catch(CDaoException* e)
    {
        m_dbStudentReg.m_pWorkspace->Rollback( );
        AfxMessageBox( "Failed to remove student." );
        e->Delete( );
        return FALSE;
    }
    m_rsStudentSet.Close( );
}

For information about the try/catch exception handling shown here, see the article Exceptions: Database Exceptions and the CDaoException class.

Efficiency Considerations for This Example

The transaction example shown in Transaction Example shows you how to do transactions. But in some cases, as in deleting records, transactions may not be most efficient approach. In fact, there are two more efficient approaches to deleting the student record along with all related records for that student:

Transactions do have a role to play, of course. The point is that you should use the best approach for the particular task.

Additional Reading About Transactions

For more information about transactions, see the following topics in DAO Help:

In the Class Library Reference, see: CDaoWorkspace, especially the BeginTrans, CommitTrans, Rollback, and SetIsolateODBCTrans member functions.

Also see CDaoRecordset, especially the AddNew, Edit, Update, Delete, IsBOF, and IsEOF member functions.

See Also   DAO: Where Is..., DAO Recordset