21.1.2 事务
在数据库上下文中,事务的概念是为了在必要时安全地取消操作。事务把对数据库的一系列定义明确地更改组合成单个操作,如果出现错误,那么在事务完成之前的任何时间点,可以撤消(或者回滚)所有更改。显然,如果一个更新在部分完成时失败,例如由于硬件问题而失败,那么它对数据库的完整性可能会有灾难性的影响。事务不仅仅是对单个表的更新。它可以对数据库进行非常复杂的操作,包括对多个表进行一系列的更改,而且可能需要很长的时间才能完成。在这些情况下,如果要保证数据库的完整性,实际上必须做到支持事务。
利用基于事务的操作,数据库系统可以管理事务的处理,记录恢复信息,这样在出现问题时,就可以撤消事务对数据所做的所有操作。事务事件记录在磁盘上的日志文件中,因此即使计算机断电,系统也可以通过读取该日志中的条目进行恢复。使数据库操作基于事务以后,就可以防止数据库在处理期间出现错误。通常,事务处理将根据需要在处理过程中锁定记录,它还保证其他数据库用户在访问已经由事务更改的数据时,能够马上看到所做的修改。
大型计算机上的大部分大型商业数据库系统都支持事务,但是对于在PC上运行的数据库系统来说,情况并非始终如此。尽管这样,MFC中的CDatabase类却支持事务,碰巧,Microsoft ODBC又支持Access数据库,所以可以对Northwind数据库试验一下事务处理。
CDatabase事务操作
事务是通过CDatabase类对象的成员来管理的,该对象提供到数据库的连接。对于给定的连接,要确定是否支持事务,需要调用CDatabase对象的CanTransact()成员。如果支持事务,这个函数将返回TRUE。CDatabase对象还有一个CanUpdate()成员,如果数据源是只读的,它将返回FALSE,不过这种情况很少。
CDatabase对象有3个成员函数参与事务处理,见表21-3。
表 21-3
|
BeginTrans()< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> |
在数据库上启动一个事务。在调用
CommitTrans()或Rollback()之前,后
续的所有记录集操作都是这个事务的
一部分。如果事务启动成功,这个
函数将返回TRUE |
|
CommitTrans() |
提交事务,完成作为事务一部分的所有
记录集操作。如果出现错误,这个函数
将返回FALSE,在这种情况下,数据源
的状态是不确定的 |
|
Rollback() |
回滚调用BeginTrans()函数以来执行的
所有记录集操作,并将数据源恢复到
调用BeginTrans()函数时的状态 |
事务中事件的顺序非常简单:
调用BeginTrans()函数,启动事务。
根据需要调用记录集的Edit()、Update()、AddNew()函数。
调用CommitTrans()函数,完成事务。
在事务的范围之外,调用Update()时将对记录集执行Edit()或AddNew()操作。在事务的范围内,调用CDatabase对象的CommitTrans()成员之前,这些操作是不执行的。如果需要在调用BeginTrans()之后结束事务,只需调用Rollback()函数。
CommitTrans()和Rollback()的执行可能会带来问题-- 例如记录集中正在被操作的位置可能丢失,所以需要在程序中采取某种措施,以便在完成或终止事务后恢复记录指针。CDatabase对象中有两个成员可以提供帮助。在调用CommitTrans()之后需要调用CDatabase的成员GetCursorCommitBehavior(),在调用Rollback()之后需要调用GetCursorRollbackBehavior()。这两个函数将返回下列3个int型数值之一,它们表明应当采取的动作,见表21-4。
表 21-4
|
SQL_CB_PRESERVE |
记录集与数据源的连接不受提交
或回滚操作的影响,所以不用
采取任何动作 |
|
SQL_CB_CLOSE |
需要调用记录集对象的Requery() ,
恢复记录集中的当前位置 |
|
SQL_CB_DELETE |
必须通过调用记录集对象的Close()
成员关闭记录集,如果必要的话,
必须重新打开记录集 |
实际使用事务时,还有其他一些问题,因为使用的特定驱动程序可能影响打开记录集的时间。对于一些驱动程序来说,必须在调用BeginTrans()之前打开记录集。对于另一些驱动程序来说,除非在调用BeginTrans()之后打开记录集,否则Rollback()将不进行操作。Microsoft Access ODBC驱动程序就是例证。在应用程序中使用事务之前,需要了解将要使用的特定驱动程序。