假设你想用ATM自动取款机把你储蓄存款帐户上的一笔钱转帐到你的经常帐户上去,在钱已经从存款帐户上出来正在转到经常帐户的时候,电脑突然崩溃!你的钱去哪了?不要担心,事务处理程序会使它非常。
仔细想想银行在幕后要做些什么工作,你一定想当然地认为银行在进行存款、提款、转帐等工作的中间什么也没干。公司、银行甚至国家每天要电子转帐几百万美圆,如果这笔资金不保险的话,那世界金融市场将会整个崩溃。
让我举一个简单的例子来说明事务处理程序的重要性。在第一国家银行中,客户可以在任何时间存款,他们也可以从他们的帐户上提款,只要所提款额小于或等于帐户中的金额。所以,拥有多个帐户的客户可以将钱款在帐户之间来回转帐。
FoxPro应用程序使用帐户类管理银行中的帐户。这个类中包含两种方式: Deposit() 和 Withdraw()。如果系统失败,这两种方式中的一种有可能会另更新数据库操作失败,比如在取款和存款结束之前电源断掉,或者帐户中没有足够的钱时,取款失败。
系统设计者要对资金在帐户见的转帐进行严格的测试。这需要往一个帐户上存款,而同时从另一个帐户取款。注意这里是同时。提款和存款不能顺序发生;他们必须同时发生,这笔转帐资金不在这个帐户或者不在那个帐户,这都是不能接受的。要么存款和提款同时成功,要么同时失败。我们该怎样做呢?
ACID测试
一笔事务其实就是数据库中收到保护的一组更新数据。所有在事务处理开始和事务结束期间的数据库改变都是受到保护的。理想情况下,事务处理程序应当能通过原子的、一致的、独立的、耐久的ACID(Atomic、 Consistent、 Isolated、 Durable)测试。理想情况下,一笔事务应当能经受住这种ACID测试。
在化学上,原子是拥有所有元素特性的最小的不可分割的单位。同样,一个原子级的事务也是最小的不可分割的单位。在转帐的例子中,一个完整的事务处理需要改变两个帐户,只改变一个帐户是不合理的。
一致性意味着事务处理正确地转换了系统状态。要么是资金离开一个帐户进入另一个帐户,要么是都保持不变---只有这两种可能的状态。如果系统没有得到转换后状态,就回到没有转换时的状态而不会停在中间。
独立性保证任何其他的事务都不能看到一个处在不完整状态下的事务处理。尽管实际上在钱款被提走而还没有存入另一个帐号期间有一个远远小于一秒的间隔,系统中的其他事务也不会知道的。
耐久性表示事务处理能在系统失败时保存完好。一个事务处理应当能够承受所有的失败,包括、进程、通信以及媒体失败等等。
FoxPro开发人员怎样做才能为应用程序提供事务处理的可靠保护呢?而且,应当怎样才能以高效、快捷的方式实现呢?怎样将事务处理的保护集成到多种应用程序的体系结构中呢?在这篇文章中,我们来看看如何在一个健壮、可升级和面向对象的应用程序中进行事务处理,这其中包括本地的和远程的数据。我们还会介绍一些事务处理的新技术。
VFP transaction basics
使用带有本地VFP数据的事务处理时,要记住第一件事是事务录中不包括空闲表格。事务处理的表格都放在数据库中;要记住的第二件事是要使事务处理尽量简单,使事务从开始到结束的时间尽量短,因为其他用户在这段时间不能访问这个事务处理涉及到的任何记录。
使用BEGIN TRANSACTION命令开始,你对数据所做的任何改动都将受到保护,一直到END TRANSACTION 或 ROLLBACK 命令发布。END TRANSACTION命令发布后,所有的改变就生效了。ROLLBACK命令的发布则将所有的改变失效。这有一个简单的例子。
CREATE DATABASE mydatabase
SET DATABASE TO mydatabase
CREATE TABLE mytable (myfield I)
?"Record count = " + STR(RECCOUNT("mytable"))
*-- 第一笔事务
BEGIN TRANSACTION
INSERT INTO mytable (myfield) VALUES (1)
END TRANSACTION
?"Record count = " + STR(RECCOUNT("mytable"))
*-- 第二笔事务
BEGIN TRANSACTION
INSERT INTO mytable (myfield) VALUES (2)
ROLLBACK
?"Record count = " + STR(RECCOUNT("mytable"))
在这个例子中,首先创建一个数据库和一个包含在其中的表格。这个表格有一个整型数据类型的字段。例子中有两个事务。在第一笔事务中,加一个记录到表格中,以END TRANSACTION结束说明这笔事务已经提交。注意记录数,在事务开始前是0,在END TRANSACTION 命令结束后是1。
第二笔事务因为最后执行了ROLLBACK 命令没有成功。注意:尽管在事务过程中又插入一个新记录,在ROLLBACK命令之后记录数仍然为1,数据库的改变没有提交,表格中的数据仍然保持原样。
事务嵌套
还是让我们看看我们的上一个国家银行的例子,它的目的是创建一个用来管理存款、提款的帐目对象以及一个用来保护钱款转帐时的转帐对象。FoxPro可以很容易地实现这个性能。VFP允许事务嵌套的深度多达五层。对所有事务的提交和放弃操作都由最外面的事务控制。 (第一个BEGIN TRANSACTION)。
USE mytable
?"Transaction level = " + STR(TXNLEVEL()) +
" Record count = " + STR(RECCOUNT("mytable"))
*-- 外层的事务处理
BEGIN TRANSACTION
?"Transaction level = " + STR(TXNLEVEL()) +
" Record count = " + STR(RECCOUNT("mytable"))
*-- 里层的事务处理Inner transaction
BEGIN TRANSACTION
INSERT INTO mytable (myfield) VALUES (6)
?"Transaction level = " + STR(TXNLEVEL()) +
" Record count = " + STR(RECCOUNT("mytable"))
*-- 提交里层的事务
END TRANSACTION
?"Transaction level = " + STR(TXNLEVEL()) +
" Record count = " + STR(RECCOUNT("mytable"))
*-- 放弃外层的事务
ROLLBACK
?"Transaction level = " + STR(TXNLEVEL()) +
" Record count = " + STR(RECCOUNT("mytable"))
这个例子是两级事务嵌套。在每个步骤中,显示了事务的级别和表格中记录的个数。TXNLEVEL()功能返回事务的级别。在每个BEGIN TRANSACTION 命令后, TXNLEVEL()返回第二大的数目,同时在里层的事务表格中插入一条记录,并且在END TRANSACTION命令后事务被提交。注意TXNLEVEL()从二减小到一。当最外层的事务被放弃后,里层事务中那条插入的记录失效,表格的内容恢复原样。
小结
事务嵌套是银行用来解决转帐问题的关键。转帐对象在最外层,帐目对象则在里层的事务级别。如果里层有两笔事务都提交了,则外层的事务也提交。但是如果里层的两笔事务中有一笔失败,则外层的事务恢复原样。即使是当一笔事务成功后,数据库的改变已经提交,最外层事务的放弃仍然会使所有内部事务所做的变化恢复原样。
【责编:admin】
--------------------next---------------------