TN068:使用 Microsoft Access 7 ODBC 驱动程序执行事务
注意
以下技术说明在首次包括在联机文档中后未更新。 因此,某些过程和主题可能已过时或不正确。 要获得最新信息,建议你在联机文档索引中搜索热点话题。
此说明介绍在使用 MFC ODBC 数据库类和 Microsoft ODBC Desktop Driver Pack 版本 3.0 中包含的 Microsoft Access 7.0 ODBC 驱动程序时如何执行事务。
概述
如果数据库应用程序执行事务,须注意的一点是,在应用程序中调用 CDatabase::BeginTrans
和 CRecordset::Open
时一定要按正确的顺序调用。 Microsoft Access 7.0 驱动程序使用 Microsoft Jet 数据库引擎,而 Jet 要求应用程序不在任何具有打开的游标的数据库上启动事务。 对于 MFC ODBC 数据库类,打开的游标等同于打开的 CRecordset
对象。
如果在调用 BeginTrans
前打开某个记录集,可能看不到任何错误消息。 但是,当调用 CRecordset::Update
后,应用程序所做的任何记录集更新都会成为永久性更新,并且调用 Rollback
后不会回滚更新。 若要避免此问题,必须先调用 BeginTrans
,然后再打开记录集。
MFC 检查驱动程序功能是否发生了游标提交和回滚行为。 类 CDatabase
提供了两个成员函数 GetCursorCommitBehavior
和 GetCursorRollbackBehavior
,用于确定任何事务对打开的 CRecordset
对象的影响。 对于 Microsoft Access 7.0 ODBC 驱动程序,这些成员函数返回 SQL_CB_CLOSE
,因为 Access 驱动程序不支持游标保留。 因此,必须在 CommitTrans
或 Rollback
操作后调用 CRecordset::Requery
。
如果需要一个一个地执行多个事务,则不能在第一个事务之后调用 Requery
然后启动下一个事务。 必须在下一次调用 BeginTrans
之前关闭记录集,以满足 Jet 的要求。 此技术说明介绍了两种处理这种情况的方法:
在每个
CommitTrans
或Rollback
操作之后关闭记录集。使用 ODBC API 函数
SQLFreeStmt
。
在每个 CommitTrans 或回滚操作之后关闭记录集
在启动事务之前,应确保记录集对象已关闭。 调用 BeginTrans
后,调用记录集的 Open
成员函数。 在调用 CommitTrans
或 Rollback
后立即关闭记录集。 请注意,重复打开和关闭记录集可能会降低应用程序的性能。
使用 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
,可以在提交或回滚第一个事务后调用该函数来启动下一个事务。 若要编写此类函数,请执行以下步骤:
将
CRecordset::Requery( )
的代码复制到新函数。在调用
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_strFilter 或 m_strSort,请不要使用此技术。 在这种情况下,应在每次 CommitTrans
或 Rollback
操作后关闭记录集。