本文基于Michael Zhuravlev (mikus@mail.ru)所写的文章
InterBase 和 Firebird服务器事务的模式
Interbase支持如下事务隔离级别:
READ COMMITTED RECORD_VERSION
READ COMMITTED NO RECORD_VERSION
SNAPSHOT
SNAPSHOT TABLE STABILITY
SNAPSHOT 隔离级别
对应与ANSI/ISO定义的REPEATABLE READ级别.程序启动一个事务时创建一个数据库的镜像.这个镜像一直持续到事务结束.允许读取并发事务修改的数据,但不能修改这些数据. 修改其他事务更新的数据将引起死锁(SQLCODE = -913). 因此是不可能修改其他并发事务更新的数据的,即使是这些并发事务已经结束.因为镜像不会在体现出当前数据库的状态(死锁. Update conflicts with concurrent update. SQLCODE = -913).
SNAPSHOT级别具有最高的隔离级别但同时如果数据库有很多并发事务会阻碍数据更新.使用这个级别可在同一个数据库同一个事务的任意时刻中获取唯一的查询结果. 是Interbase 中默认的隔离级别.
READ COMMITTED RECORD_VERSION隔离级别
与ANSI/ISO 中的READ COMMITTED级别相对应.事务可以读取其他未结束事务提交的修改.修改其他未结束事务提交的变更数据将引起死锁(SQLCODE = -913).与READ COMMITTED ANSI/ISO不同这里允许修改其他未结束事务提交的数据.这种模式会引起幻读和不确定的数据.其可能应用于在事务中只对数据库查询一次而且不存储查询结果.
READ COMMITTED NO RECORD_VERSION 隔离级别
这是与READ COMMITTED RECORD_VERSION模式类似的级别,但即使简单的读取其他事务修改的数据也会引发死锁(SQLCODE = -913).在并发事务结束后才能读取和修改这些变更的数据.
因此NO RECORD_VERSION不适合与用在有很多查询语句的情况因为记录只能在死锁发生前读取到.
SNAPSHOT TABLE STABILITY 隔离级别
阻止其他事务修改表.其他事务只有读取权限.
Interbase和ANSI的隔离模式比较
Interbase | Interbase API | ANSI/ISO |
READ COMMITTED | isc_tpb_read_committed, | READ COMMITTED |
READ COMMITTED | isc_tpb_read_committed, | READ COMMITTED |
SNAPSHOT | isc_tpb_concurrency | SERIALIZABLE |
SNAPSHOT TABLE STABILITY | isc_tpb_consistency |
|
权限模式
所有的隔离级别都有一个附加的权限选项:只读(READ ONLY)或读写(READ WRITE).尽量在服务端开启只读事务,这样就不必保存对数据库的修改来查找和其他事务的冲突了.READ WRITE模式是默认设置的.
不同级别事务的交互
| isc_tpb_concurrency, | isc_tpb_concurrency | |||
isc_tpb_write | isc_tpb_read | isc_tpb_write | isc_tpb_read | ||
isc_tpb_concurrency, | isc_tpb_write | 可能冲突 | - | 冲突 | 冲突 |
isc_tpb_read | - | - | - | - | |
isc_tpb_concurrency | isc_tpb_write | 冲突 | - | 冲突 | 冲突 |
isc_tpb_read | 冲突 | - | 冲突 | - |
WAIT 和 NO WAIT等待模式
如果在等待模式下发生冲突事务将进入等待状态直到并发事务结束.然后才会继续处理数据库或返回记录冲突信息的错误码.只有在隔离级别允许修改已经被阻塞的记录时才能使用等待模式.即READ COMMITTED级别.在默认的SNAPSHOT级别下使用等待模式是无效的.除此之外应用程序在这个模式下执行查询会有一段等待延迟.推荐使用NO WAIT模式+错误码的方案.WAIT是默认的模式.
提交和回滚事务
Interbase中的所有数据库操作(包括DDL命令)都执行在事务上下文中.事务分两种类型:隐式和显式.隐式事务含有READ WRITE WAIT SNAPSHOT参数,执行任何命令后自动启动并直到事务结束(提交或回滚). Interbase服务器也允许显式的指定参数后启动事务,并可以一个客户端同时执行多个事务.如下命令用来结束事务:COMMIT,ROLLBACK, COMMIT RETAINING(提交事务并保存事务上下文). ROLLBACK RETAINING在InterBase6.0版本引入.
COMMIT RETAINING命令提交事务但马上使用完全一致的参数重新启动一个新事务(这里和其他文档所述有出入).其保存同样的游标,这样客户端程序不必重新创建游标并获取数据.
注意: InterBase事务更多信息请见Programmer's Guide and API Guide.
使用FIBPlus组件
TpFIBTransaction 组件
TpFIBTransaction组件控制使用FIBPlus时所有的事务.组件有如下关键属性:
TRParams
TimeoutAction
Timeout
TPBMode
及方法:
StartTransaction
Commit
CommitRetaining
Rollback
RollbackRetaining
事务模式在TRParams属性中以字符串列表的方式进行设置.模式选项间没有逗号间隔.更多事务选项信息见Interbase API Guide.
除了可以在TRParams属性中设置事务模式,还可以设置TPBMode.这个属性有多个预定义的隔离级别: tpbDefault, tpbReadCommitted, tpbRepeatableRead. 如果设置为tpbDefault以外的值,TRParams属性的值将被忽略.
存取模式:
· isc_tpb_write - READ WRITE
· isc_tpb_read - READ ONLY
等待模式:
· isc_tpb_nowait - NO WAIT
· isc_tpb_wait - WAIT
隔离级别:
· isc_tpb_read_committed, isc_tpb_no_rec_version - READ COMMITTED NO RECORD_VERSION
· isc_tpb_read_committed, isc_tpb_rec_version - READ COMMITTED RECORD_VERSION
· isc_tpb_concurrency - SNAPSHOT
· isc_tpb_consistency - SNAPSHOT TABLE STABILITY
注意:不要设置isc_tpb_version3参数.
使用Active或InTransaction属性检查事务是否激活.两个属性都调用了GetInTransaction方法.
TimeoutAction属性设置事务结束后执行的默认动作.默认的TimeoutAction 值为TACommit,提交变更并关闭游标.
Timeout属性定义一个毫秒间隔.超过这个时间间隔后事务自动结束并执行TimeoutAction制定的相应动作.这是使用TTimer控件实现的,如果Timeout设置为0默认动作永远不会执行.
FIBPlus 中的隐式事务
如果没有调用TpFIBTransaction.StartTransaction而 打开数据集, TpFIBDataSet将检查Options. poStartTransaction属性值.如果为True则自动调用相应TpFIBTransaction 组件的StartTransaction方法.这种方式启动的事务在查询结束后不会自动关闭.需要手动提交或回滚事务.
FIBPlus 中的显式事务
为更好控制事务需要显式调用TpFIBTransaction.StartTransaction.而后可以提交或回滚数据变更.提交或回滚操作结束事务并关闭与其相关的所有数据集. CommitRetaining 提交事务并重启事务而且保留所有上下文. CommitRetaining 还有一个好处是由于数据集没有关闭用户还可继续修改数据.
使用默认的Timer和Action
使用TimeoutAction 和 Timeout可以实现周期性提交数据修改从而降低事务间的冲突概率.为此将Timeout设置为不是很高的值,如1000,TimeoutAction=TACommitRetaining,将实现每秒执行一次COMMIT RETAINING.
注意:
· 不要忘记这时使用Timer控件实现显式的事务控制,帮助执行StartTransaction 和 Commit/Rollback.使用Timer控件启动的事务无法手动停止.
· 在BDE5.1的bdereadme.txt中有一个非常隐晦的描述” Soft commits are a feature of InterBase that let the driver retain the cursor when committing changes.” (InterBase的软提交特性使驱动在提交后保留了游标).不清楚软提交(即COMMIT RETAINING)原理的人会以为这个模式提交事务后并在事务之外保持打开的游标.但是这是不正确的.BDE中所有操作都是在事务上下文中执行的,因此COMMIT RETAINING简单的克隆了一个被提交的事务.认为其可能重启启动一个事务,从服务器上下载数据,执行COMMIT RETAINING然后以离线的方式查看数据,是很初级的想法.这种方式可以确保数据感知控件一直拥有一个开启的事务.
· 脱离事务上下文编辑数据的方式请见FIBPlus的CachedUpdates模式.
不要设置Timeout := 1,TimeoutAction := TACommitRetaining,希望到达快速的数据下载,结束事务并获取到内部缓冲区中的数据.这是很糟糕的:程序每毫秒都向服务器提交变更(事实上很难实现),这会增加网络流量.
如果TimeoutAction等于TACommit或TARollback,事务将在第一次触发Timer事件时结束.
使用CachedUpdates
设置CachedUpdates =True将改变程序的工作方式.执行一个查询,获取所有记录保存在客户端,关闭数据库连接并在事务上下文之外编辑数据.修改完毕后启动数据库连接.然后还可以提交数据的更改.