事务控制
审查状态
从这一节开始,到这一章末尾的所有部分都正在等待技术和编辑审查。
在Firebird数据库的一切都发生在事务中。工作单元从起始点和结束点之间是相互隔离的。更改数据保持是可逆的,直到客户端应用程序指示服务器提交那一刻。
Firebird数据库有一个SQL语句小词典用于客户端应用程序用于启动、 管理、 提交和反向(回滚)事务从所有数据库任务的边界:
SET TRANSACTION: 用于配置和启动事务
COMMIT: 用信号通知工作单元的结束并将更改永久地写入数据库
ROLLBACK: 反向在事务中执行的更改
SAVEPOINT: 标记已经完成的工作在日志中的位置,用于需要部分回滚的情况下
RELEASE SAVEPOINT: 用于删除创建的保存点
用途: 配置和启动一个事务
用于: DSQL, ESQL
语法:
SET TRANSACTION
[NAME tr_name]
[READ WRITE | READ ONLY]
[[ISOLATION LEVEL] {
SNAPSHOT [TABLE STABILITY]
| READ COMMITTED [[NO] RECORD_VERSION] }]
[WAIT | NO WAIT]
[LOCK TIMEOUT seconds]
[NO AUTO UNDO]
[IGNORE LIMBO]
[RESERVING | USING ]
::= [, ...]
::= tablename [, tablename ...]
[FOR [SHARED | PROTECTED] {READ | WRITE}]
::= dbhandle [, dbhandle ...]
表 9.1. SET TRANSACTION语句参数
要保留的表的列表
参数 | 描述 |
tr_name | 事务名称.仅在ESQL中适用 |
seconds | 以秒为单位的语句等待时间,以防发生冲突 |
tables | |
dbhandles | 数据库可以访问的数据库的列表。仅在ESQL中适用 |
table_spec | 表保留规定 |
tablename | 要保留的表的名称 |
dbhandle | 数据库可以访问的数据库的句柄。 |
SET TRANSACTION语句配置事务并启动它,通常,只有客户端应用程序启动事务。例外是当服务器启动一个自治事务或对于某些后台系统线程/进程事务,如清扫线程(强制垃圾回收)。
客户端应用程序可以启动任意编号的并行事务。限制确实存在,总运行的事务编号在所有客户端应用程序使用一个特定的数据库,从数据库恢复的备份副本或从最初创建的数据库的那一刻。限制是231 - 1,或者2147483647。
在SET TRANSACTION语句中所有的子句是选项,如果语句启动一个事务在里面没规定子句,那么事务将以默认值启动对于访问方式、锁解决方式及隔离及别,它们是:
SET TRANSACTION
READ WRITE
WAIT
SOLATION LEVEL SNAPSHOT;
服务器按事务顺序分配整数编号。每当客户端启动任何事务服务器向客户端发送的事务 ID要么使用显式定义要么使用默认。可以检索此编号在 SQL 中使用上下文变量 CURRENT_TRANSACTION。
事务参数
事务的主要参数有:
• 数据访问方式(READ WRITE, READ ONLY)
• 锁解决方式(WAIT, NO WAIT) 带有选项 LOCK TIMEOUT 规定
• 隔离级别 (READ COMMITTED, SNAPSHOT, TABLE STABILITY)
• 保留或释放表机制(the RESERVING clause)
务事名称
可选名称属性定义事务的名称。使用这个属性只在嵌入式SQL中有效,在ESQL中应用程序,命名事务可以使得在一个应用程序中同时有多个事务活动。如果命名事务被使用,具有相同名称的宿主语言变量必须被声明和初始化对每个命名事务。这是防止动态事务名称指定的一个限制,因此,规则在DSQL事务命名之外。
访问方式
对事务而言有两种数据库访问方式,读写和只读.
•如果访问方式是读写,在这个事务的上下文中读操作和数据更新操作这两个操作都可以,这个默认方式.
•如果访问方式是只读,那么只有SELECT操作能被执行在这个事务的上下文中.在这样的事务上下文中任何试图改变数据的操作都将导致数据库异常.然而,它不适用于全局的临时表(GTT),它们被允许在只读事务下更改。
锁解决方式
当多个客户端进程工作在同一个数据库时,锁可能发生当一个进程更改了表的数据一行或删除了一行提交未完成,而另一个进程试图更新或删除同一行。这样的锁被称为更新冲突。
锁可能发生在其它情形,当多个事务了隔离级别被使用时。
这两种锁解决方式是WAIT 和 NO WAIT.
等待模式WAIT Mode
在等待模式(默认模式)中,如果发生冲突在两个并行进程并发执行数据更新相同的数据库之间,等待事务将一直等待到其他事务结束提交(COMMIT)或回滚(ROLLBACK)。客户端应用程序与待事务将被搁置,直到冲突解决。
如果为WAIT事务的LOCK TIMEOUT参数指定一个值,等待将仅继续在此子句中指定的秒数。如果锁是在指定的时间间隔结束时未解决,错误消息"在等待交易的锁定超时"返回给客户端。
锁解决行为可能会有所不同,这取决于事务隔离级别。
无等待模式NO WAIT Mode
在无等待模式中,如果有冲突发生事务将立即抛出数据库异常.
隔离级别
保持一个数据库的工作任务同另一个分离就是隔离。被一个语句所做的更改成为可见的对于在相同事务所有其余语句的执行,不论其隔离级别.其它事务在进程中的改变对于当前务保持不可见,只要它们保持未提交.另一个事务要提交工作时,隔离级别有时由其它属性决定事务如何交互,
ISOLATION LEVEL属性定义了事务被启动时的隔离级别,它是用于确定其对其他并发运行事务的行为的最重要的事务参数.
在Firebird中有三隔离级别被支持:
• 快照 SNAPSHOT
• 快照表稳定性 SNAPSHOT TABLE STABILITY
• 读提交 READ COMMITTED 有两个规格 (NO RECORD_VERSION 和 RECORD_VERSION)
SNAPSHOT 隔离级别
SNAPSHOT隔离级别是默认的.允许事务仅读取事务本身启动前那些已经被提交的改变,在活动事务中无法看到其他并行事务修改的数据.事务只能看到其自己修改的变更.当前事务的变更只有当它要么完全提交要么完全回滚对一个新的事务才是可见的,但如果它只是回滚到一个保存点则也不见。
自治事务
由快照事务启动的自治事务所做的更改在在快照事务本身的上下文中看不见。
SNAPSHOT TABLE STABILITY 隔离级别
SNAPSHOT TABLE STABILITY隔离级别是最严格的,同SNAPSHOT相比,一个在SNAPSHOT TABLE STABILITY中的事务只能看到当前事务被启动前的那些已经提交完成的修改,一旦SNAPSHOT TABLE STABILITY隔离级别的事务被启动后,没有其它事务能对数据库中的任何变更为挂起的表做任何改变,其它事务能读取其它的数据库.但任何企图进行插入、更新或删除的并行处理将导致冲突异常。
RESERVING语句可被用于允许其它事务在某些表更改数据。
如果任何其它事务有未提交的数据变更挂起在任何数据库表中,在一个事务使用SNAPSHOT TABLE STABILITY 隔离级别被启动之前,那么试图启动SNAPSHOT TABLE STABILITY 隔离级别事务将导致一个异常.
READ COMMITTED 隔离级别
READ COMMITTED 隔离级别允许所有数据的变更,其它事务已经提交的变更立即被当前未提交的事务可见,未提交的更改对于READ COMMITTED事务是不可见的
要检索您感兴趣的表中的行的更新的列表 — —"刷新"— — 只是 SELECT 语句需要请求再一次,虽然仍未提交READ COMMITTED事务。
记录版本 RECORD_VERSION
两个修改参数之一可为READ COMMITTED事务来指定,这取决于某种解决冲突所需:RECORD_VERSION和NO RECORD_VERSION。正如名字所暗示,它们是相互排斥的。
• NO RECORD_VERSION (默认值)是一种两个阶段的锁定机制:它将使得事务无法写入被另一事务更新挂起的任何行。
- 如果NO WAIT被指定为锁解决策略,它将立即抛出一个锁冲错误。
- 如果WAIT被指定为锁解决策略,它将等待直到其它事务要么提交要么回滚。如果其它事务被回滚,或是如果被提交且它的事务ID比当前事务ID老,那当前事务的变更是被允许的.如果其它的事被提交且它的事务ID比当前事务ID新,则一个锁冲错误被返回.
•带上RECORD_VERSION,事务读取最新提交版本的行,不考虑行的其他的挂起版本。锁解决策略(WAIT或NO WAIT)不会影响的事务行为,不论其以何种方式启动。
不自动撤销 NO AUTO UNDO
NO AUTO UNDO选项会影响回滚事件中未使用的记录版本(垃圾)的处理。带有NO AUTO UNDO被标识,NO AUTO UNDO
ROLLBACK语句只标记事务为回滚,没有删除在事务中创建的未使用的记录版本。它们被留下来稍后被垃圾收集器擦掉。
当很多单独的语句执行条件变更数据时NO AUTO UNDO可能是有用的,因为在大部分时候该事务很可能被成功提交。
对于没有变更的事务,没有NO AUTO UNDO选项被忽略。
忽略遗弃事务 IGNORE LIMBO
此标志用于发出信号,由LIMBO事务创建的记录将被忽略。事务是被保留"在遗弃中",如果两阶段的第二阶段提交失败。
历史笔记
IGNORE LIMBO表面的TPB参数isc_tpb_ignore_limbo,可用的API从InterBase时代开始,主要由gfix使用。
保留 RESERVING
RESERVING子句在SET TRANSACTION语中保留表列表中指定的表.保留一个表可以防止其他事务更改,或甚至包括某些参数从它们中读取数据当事务正在运行时。
RESERVING子句也能用于指定一个能被其它事务更改的表清单,即使事务被启动带有SNAPSHOT TABLE STABILITY隔离级别。
一个RESERVING子句用于指定尽可能多的需要被保留表。
RESERVING子句选项
如果其中一个关键词SHARED或PROTECTED被省略,那么SHARED被假定。如果整个FOR子句被省略,FOR SHARED READ被假定。四访问选项的名称和兼容性对保留表是不明显的。
表9.2。RESERVING的访问选项的兼容性
SHARED READ | SHARED WRITE | PROTECTED READ | PROTECTED WRITE | |
SHARED READ | Yes | Yes | Yes | Yes |
SHARED WRITE | Yes | Yes | No | No |
PROTECTED READ | Yes | No | Yes | No |
PROTECTED WRITE | Yes | No | No | No |
RESERVING子句标志的组合对并发访问依赖于并发事务的隔离级别:
•SNAPSHOT 隔离
- 并发SNAPSHOT事务加上 SHARED READ不会影响另一个的访问
- 并发SNAPSHOT和READ COMMITTED事务加上 SHARED WRITE不会影响另一个的访问,但是它们阻塞SNAPSHOT TABLE STABILITY隔离级别指定的表,要么是读要么是写.
- 并发事务带上任何隔离级别同PROTECTED READ仅能保留表读数据,任何试图写都将导致异常.
- PROTECTED WRITE同并发 SNAPSHOT事务和READ COMMITTED 隔离不能写入指定的表。带有SNAPSHOT TABLE STABILITY隔离的事务不能读或写保留表。
• SNAPSHOT TABLE STABILITY 隔离
-所有带有SHARED READ的并发事务,不考虑它们的隔离级别,能从保留表读或写入(如果在READ WRITE方式).
-并发SNAPSHOT事务加上 READ COMMITTED和SHARED WRIT能从指定表读取数据或写入(如果在READ WRITE方式),但从并发访问这些表与事务带上SNAPSHOT TABLE STABILITY被完全阻塞当这些事务是活跃的时候.
- 并发事务带上任何隔离级别同PROTECTED READ仅能保留表读数据。
- 使用PROTECTED WRITE同并发 SNAPSHOT事务和READ COMMITTED 隔离能读但不能写入保留的表。由事务带有SNAPSHOT TABLE STABILITY隔离级别的存取被过完全阻塞.
• READ COMMITTED 隔离
- 使用 SHARED READ,所有的并发事务同任隔离级别,能从保留表读或写入(如果在READ WRITE方式).
- SHARED WRITE允许所有的事务在 SNAPSHOT 和 READ COMMITTED 隔离中去从指定的表读或写入(如果在READ WRITE方式),事务带有SNAPSHOT TABLE STABILITY隔离级别的存取被过完全阻塞.
-使用 PROTECTED READ,并发事务同任隔离级别,只能从保留表读.
- 使用 PROTECTED WRITE,同并发 SNAPSHOT事务和READ COMMITTED 隔离能读但不能写入保留的表。由事务带有SNAPSHOT TABLE STABILITY隔离级别的存取被过完全阻塞.
提示
在嵌入式 SQL 中,可以使用 USING 子句来节省系统资源,通过限制数据库事务可以访问到枚举列表(数据库)。USING同RESERVING不兼容。USING子句在DSQL的SET TRANSACTION语法中是不持的.
参阅: COMMIT, ROLLBACK