18.3.2.2 使用隐式控制
在缺省情况下,Delphi通过BDE为应用程序提供隐式事务控制。当应用程序处于隐式事务控制时Delphi为DataSet中的写每个记录进行隐式事务控制。它提交每一个独立的写操作,如Post和Append Record。
使用隐式事务控制是容易的,它保证最小的记录更新冲突和数据库的一致性视图。另一方面,因为写入数据库的数据的每一行都要进行事务控制, 所以隐式事务控制将导致网络过忙和应用程序性能下降。
如果采用显式事务控制,就能选择最有效的时机来开始、提交和终止事务,特别是在开发多用户环境下的客户应用程序运行访问远程SQL服务器,就更应该采用显式控制。
18.3.2.3 使用显式事务控制
有两种协作又独立的方式可运用于Delphi数据库应用的事务控制:
● 使用TDatabase部件的方法和属性
● 使用TQuery部件中的传递式SQL。这种方式只有在Delphi Client/Server Suite版中才有效,SQL Links将SQL表达式直接传给过程SQL或ODBC服务器
使用TDatabase部件的方法和属性的好处是提供了清晰的、轻便的、与特定数据库或服务器无关的应用能力。
使用传递式SQL的主要好处在于可以运用特定服务器的先进事务管理能力。
1. 使用TDatabase的方法和属性
下表中列出了TDatabase部件中用于事务管理的方法和属性以及它们的使用方法:
表18.11 TDatabase用于事务显式控制的方法表
━━━━━━━━━━━━━━━━━━━━━━━━
方法或属性 作 用
────────────────────────
Commit 提交数据的修改并终止事务
Rollback 取消数据的修改并终止事务
StartTransaction 开始一个事务
TransIsolation 表述事务的独立性级别
━━━━━━━━━━━━━━━━━━━━━━━━
StartTransaction,Commit和Rollback是供应用程序在运行时调用开始事务,控制事务并且保存或放弃所做数据修改的方法。
TransIsolation是TDatabase部件的用于控制作用于相同表的不同事务之间如何交互的属性。
⑴ 开始一个事务
当你开始一个事务时,后来的所有读写数据库的表达式都发生在那次事务的环境中。每个表达式都是其中一部分。任何表达式所做的修改,要么成功地提交给数据库,要么每一个修改都被取消。考虑一个在ATM上的银行传输问题。当顾客决定将钱从存款帐户转到支付帐户时,在银行数据库记录上必须发生两个修改:
● 存款帐户必须记入借方
● 支付帐户必须记入贷方
如果出于某种原因,其中的一个操作不能被完成,那么任何一个操作都不应该发生。因为这些操作是相关的,它们应该发生在同一个事务中。
为了开始Delphi应用程序中的一个事务,需要调用TDatabase部件中的StartTransaction方法:
DatabaseInterBase.StartTransaction;
此后的所有数据操作都发生在最近一个事务的环境中,直到该次事务通过调用Commit或Rollback显式地终止为止。
那么,应当将事务保持多久呢?理想状态下,只要需要,多久都行。事务的活跃状态越长,同时访问数据库的用户越多,在你的事务的生命其中,更多的并发、同时的事务开始和终止,于是当试图提交修改时,与其它事务冲突的可能性更大。
⑵ 提交一个事务
为了做永久性修改,事务必须使用TDatabase部件的Commit方法提交。执行提交表达式将保存数据库的修改并终止事务。例如,下列表达式将终止在上例中开始的事务:
DatabaseInterBase.Commit
Commit的调用应当置于try…except表达式中。如果一个事务不能成功提交,你就能处理错误,并重试操作。
⑶ 返转一个事务
为了取消数据库修改,必须用Rollback方法返转一个事务。Rollback 复原一个事务的修改,并终止事务,例如:下列表达式将返转一个事务:
DatabaseInterBase.Rollback;
Rollback通常发生在:
● 异常处理代码
● 按钮或菜单事件代码,如用户点按了Cancel按钮
⑷ 使用TransIsolation属性
TransIsolation属性描述TDatabase部件事务的独立级别,事务的独立级别决定了事务与其它作用于相同表的事务是如何相互作用的。在改变或设置TransIsolation 的值之前,应当相当熟悉Delphi中的事务和事务管理。
TransIsolation的缺省值是tiReadCommitted。下表中总结了TransIsolation的可能值并描述了它们的含义:
表18.12 TransIsolation属性值的含义
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
独立级别 含 义
──────────────────────────────────────
tiDirtyRead 允许读由其它同时事务写入数据库的未提交的修改。未提交的
修改不是永久性的,可能在任何时候被复原。 在这个级别你
的事务与其它事务所做的修改具有最低独立度。
tiReadCommitted 只允许读由其它同时事务提交的数据库修改。这是缺省的独
立级别。
tiRepeatableRead 允许单个的数据库读事务无法看见其它同时事务对相同数据做
的修改。这个独立级别保证了你的事务一次读一个记录,记录
的视图不会改变, 在这个级别你的事务与其它事务做的修改完
全独立。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
各种数据库服务器不同程度地支持这些独立级别,有的根本不支持。 如果请求的隔离级别不被服务器支持,Delphi将采用更高的独立级别。各种服务器支持的独立级别请参见表18.10。
如果应用程序使用ODBC与服务器交互,ODBC驱动程序必须支持独立级别。
2. 使用传递式SQL
为了能使用传递式SQL控制事物,必须:
● 使用Delphi Client/Server Suite
● 安装正确的SQL Links驱动程序
● 正确配置网络协议
● 访问远程服务器上数据库的能力
● 用BDE配置工具将SQLPASSTHROUGH MODE设置为NOT SHARED
通过传递式SQL,你可以使用TQuery、TStoredProc、或TUpdateSQL部件直接发送一个SQL事务控制表达式给远程数据库服务器;BDE本身并不处理SQL表达式,采用传递式SQL可使用户直接获得SQL服务器提供了事务控制优点,尤其是当那些控制是非标准的时。
SQL PASS THROUGHMODE 描述BDE和传递式SQL是否共享相同的数据库联接。在大多数情况下,SQLPASSTHROUGHMODE被设置SHARED AUTOCOMMIT。然而,如果你想将SQL事务控制传递给服务器,你就必须用BDE配置工具,将BDE的SQLPASSTHROUGHMODE 设置为NOT SHARED。此外,还必须为传递SQL事务控制表达式的TQuery部件建立独立的TDatabase 部件。
3. 使用本地事务
BDE还支持Paradox和dBASE上的本地事务。从代码角度而言,在本地事务和远程数据库服务器的事务之间没有什么差别。
当作用于本地数据库表的事务开始时,更新操作被记录在日志中,每个日志记录包含旧的记录缓冲区。当事务处于活跃状态,更新的记录被锁定,直到事务被提交或返转,在返转过程中,旧的记录被应用于将更新的记录恢复到原先的状态。