TN068:使用 Microsoft Access 7 ODBC 驱动程序执行事务

注意

以下技术说明在首次包括在联机文档中后未更新。 因此,某些过程和主题可能已过时或不正确。 要获得最新信息,建议你在联机文档索引中搜索热点话题。

此说明介绍在使用 MFC ODBC 数据库类和 Microsoft ODBC Desktop Driver Pack 版本 3.0 中包含的 Microsoft Access 7.0 ODBC 驱动程序时如何执行事务。

概述

如果数据库应用程序执行事务,须注意的一点是,在应用程序中调用 CDatabase::BeginTransCRecordset::Open 时一定要按正确的顺序调用。 Microsoft Access 7.0 驱动程序使用 Microsoft Jet 数据库引擎,而 Jet 要求应用程序不在任何具有打开的游标的数据库上启动事务。 对于 MFC ODBC 数据库类,打开的游标等同于打开的 CRecordset 对象。

如果在调用 BeginTrans 前打开某个记录集,可能看不到任何错误消息。 但是,当调用 CRecordset::Update 后,应用程序所做的任何记录集更新都会成为永久性更新,并且调用 Rollback 后不会回滚更新。 若要避免此问题,必须先调用 BeginTrans,然后再打开记录集。

MFC 检查驱动程序功能是否发生了游标提交和回滚行为。 类 CDatabase 提供了两个成员函数 GetCursorCommitBehaviorGetCursorRollbackBehavior,用于确定任何事务对打开的 CRecordset 对象的影响。 对于 Microsoft Access 7.0 ODBC 驱动程序,这些成员函数返回 SQL_CB_CLOSE,因为 Access 驱动程序不支持游标保留。 因此,必须在 CommitTransRollback 操作后调用 CRecordset::Requery

如果需要一个一个地执行多个事务,则不能在第一个事务之后调用 Requery 然后启动下一个事务。 必须在下一次调用 BeginTrans 之前关闭记录集,以满足 Jet 的要求。 此技术说明介绍了两种处理这种情况的方法:

  • 在每个 CommitTransRollback 操作之后关闭记录集。

  • 使用 ODBC API 函数 SQLFreeStmt

在每个 CommitTrans 或回滚操作之后关闭记录集

在启动事务之前,应确保记录集对象已关闭。 调用 BeginTrans 后,调用记录集的 Open 成员函数。 在调用 CommitTransRollback 后立即关闭记录集。 请注意,重复打开和关闭记录集可能会降低应用程序的性能。

使用 SQLFreeStmt

还可以使用 ODBC API 函数 SQLFreeStmt 在结束事务后显式关闭游标。 若要启动另一个事务,请调用 BeginTrans 后调用 CRecordset::Requery。 调用 SQLFreeStmt 时,必须将记录集的 HSTMT 指定为第一个参数,将 SQL_CLOSE 指定为第二个参数。 此方法比在每个事务开始时关闭和打开记录集更快。 下面的代码演示如何实现此技术:

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();

实现此技术的另一种方法是编写一个新函数 RequeryWithBeginTrans,可以在提交或回滚第一个事务后调用该函数来启动下一个事务。 若要编写此类函数,请执行以下步骤:

  1. CRecordset::Requery( ) 的代码复制到新函数。

  2. 在调用 SQLFreeStmt 后立即添加以下行:

    m_pDatabase->BeginTrans( );

现在,可以在每对事务之间调用此函数:

// 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()

注意

如果需要在事务之间更改记录集成员变量 m_strFilterm_strSort,请不要使用此技术。 在这种情况下,应在每次 CommitTransRollback 操作后关闭记录集。

另请参阅

按编号列出的技术说明
按类别列出的技术说明