第四章 事务管理

时间:2023-01-01 09:37:25

4、事务管理

这一章对事务做了定义以及描述了如何通过事务管理你的工作。

本章包含下列内容:

u 事务的介绍

u 事务管理概述

u 自主事务概述

事务介绍

事务是包含一个多或多个SQL语句的逻辑单位。一个事务是一个原子单位。事务中的所有SQL语句只能全部提交(应用到数据库)或者全部回滚(从数据库撤销)。

一个事务从第一个执行的SQL语句开始。一个事务在它被提交或者被回滚结束,结束事务可以显式的使用COMMIT或者ROLLBACK语句或执行一个DDL语句(隐含着事务结束)。

要说明事务的概念可以想象一个银行数据库。当一个银行客户从储蓄帐号中取出钱到活期帐号中,事务由三个独立的操作组成:

u 储蓄帐户减值

u 活期帐户增值

u 在事务日志中记录事务

Oracle必须适合两种情况。如果三个SQL语句都按照正确的顺序执行来维护帐号,事务的结果可以应用到数据库中。虽然如此,如果发生一个帐户资金不足、无效帐号或者硬件错误的问题让事务中的一个或者两个语句没有完成,整个事务必须回滚确保帐户余额是正确的。

图4-1描述了银行事务示例

第四章 事务管理

语句执行和事务控制

一个成功运行的SQL语句和提交的事务不同。成功执行意味着单个语句是:

u 解析

u 创建有效的SQL结构

u 作为一个原子单位正确运行。例如,多行更新的所有行都被修改

虽然如此,在包含语句的事务提交之前,事务都是可以回滚的,所有事务做的修改都可以撤销。一个语句能够成功运行,事务不能(因为事务不是语句,只有开始和结束,只有提交和回滚,没有成功和失败的说法)。

提交意味着一个用户显示或者隐式的要求事务的变化持久化。一个显式的请求是当用户执行COMMIT语句时。一个隐式的请求是应用程序正常结束或者一个DDL操作完成后。事务包含的SQL语句造成的修改变得持久,并对事务之后的其他用户可见。事务提交之后执行的SQL可以看到已经提交的修改。

你可以用SET TRANSACTION ..... NAME语句在你开始事务之前设置事务名称。这使得监控长时间运行的事务更加容易,解决出现问题的分布式事务也是如此。

语句级别的回滚

如果SQL语句执行的任何时候产生错误,这个语句造成的所有的影响都会回滚。回滚的结果就好像语句从没有运行过。这个操作是个语句级别的回滚。

SQL语句执行时遇到的错误导致语句级别回滚。当向主键内插入重复的数据就会产生这样的错误例子。死锁(对同一数据的争用)的SQL语句也会导致语句级别的回滚。如果在SQL语句解析时遇到了错误,比如语法错误,因为还没有运行,所以不会导致语句级别回滚。

一个SQL语句的失败只会损失它想要的执行的任何工作本身。不会导致损失当前事务之前的任何工作。如果一个语句是DDL语句,然后就会隐含提交还没有撤销的操作(即使这个DDL语句有错误也一样)。

可恢复的空间分配

Oracle提供了一种在空间分配失败事件中暂停、重新启动、执行大的数据库操作的办法。这使得管理员可以采取正确的动作,而不是Oracle数据库对用户返回一个错误。在错误环境被纠正之后,暂停的操作自动重新开始。

只有在客户端对于会话使用了ALTER SESSION语句来显示启动重新开始功能之后,一个语句才能在运行在重新开始模式(resumable)下。

当下列情况出现时重新启动的空间分配会暂停:

u 空间不足

u 达到最大数据区段

u 超过空间限额

对于不可重新开始的空间分配,这些情况会导致错误,语句被回滚。

语句的暂停导致事务的暂停。因而事务的所有资源会在语句暂停和重新启动这段时间一直持有。

当错误环境过去(例如,用户介入或者其他查询释放了排序空间),暂停的语句自动恢复执行状态。

事务管理概述

Oracle中的第一个执行的SQL语句会开始一个事务。一个执行的SQL语句是对实例产生调用的一个SQL语句,语句包括DML和DDL语句。

当事务开始时,Oracle对这个事务分配一段可用的undo表空间来保存新事务的重做条目。

一个事务在任一下列情况下终结:

u 用户提交了不附带SAVEPOINT子句的COMMIT或ROLLBACK语句

u 用户运行例如CREATE,DROP,RENAME或ALTER的DDL语句。如果当前事务中包含任何DML语句,Oracle先提交这个事务,然后将这个DDL语句作为一个新的单独的语句事务来运行和提交(注意:即使这个DDL语句错误也会如此,因为Oracle先提交事务再执行DDL)。

u 一个用户从Oracle中断连接。当前的事务被提交。

u 一个用户进程不正常中断。当前事务被回滚。

一个事务结束之后,下一个执行的SQL语句自动启动后续的事务。

注意:应用程序应该在程序中断之前显式的提交或者回滚事务。

提交事务

提交一个事务意味着事务中执行的SQL语句造成的修改持久化。

在一个事务提交修改的数据之前,会发生下列事情:

u Oracle已经产生了undo信息。Undo信息包含事务中的SQL语句修改的数据的原始值

u Oracle已经在SGA的重做日志缓存中产生重做日志条目。重做日志记录包含数据块的修改和回滚段的修改信息。在事务提交之前这些修改会写入磁盘。

u 修改已经保存在SGA的数据库缓存中。这些修改在事务提交之前会写入磁盘。

    注意:提交的事务在SGA中数据库缓存中保存的修改的数据不需要立刻由后台数据库写入进程(DBWn)写入数据文件。这个写入会在数据库认为写入效率最高的时候写入。它可能在事务提交或者事务提交之后一段时间才写入。

当一个事务被提交,会发生下列事情:

1、相关undo表空间的内部事务表记录事务被提交,事务的唯一系统修改号(SCN)被分配并保存在表中。

2、日志写入进程(LGWR)将SGA的重做日志缓存中的重做日志条目写入重组日志文件。它还将事务的SCN写入重做日志文件中。这个原子事件代表了事务的完成。

3、Oracle释放拥有的行和表上的锁

4、Oracle标识事务完成。

注意:LGWR默认情况下会同步的将重做信息写入在线重做日志文件,事务默认情况下也会等待重做信息写入磁盘,然后将提交返回给客户。虽然如此,在低事务提交级别的应用程序开发人员可以指定重做信息可以异步写入,而事务也不需要等待重做日志写入磁盘。

回滚事务

回滚的意思是在一个没有提交的事务中撤销其中SQL执行造成的数据修改。Oracle使用undo表空间(或者回滚段)来保存原始值。重做日志包含修改的记录。

Oracle可以回滚整个没有提交的事务。而且也可以回滚到未提交事务中标识为保存点(savepoint)的尾部。

所有类型的回滚都使用同样的过程:

u 语句级别回滚(语句执行错误或者死锁)

u 回滚到保存点(savepoint)

u 根据用户要求回滚

u 进程意外中断造成的事务回滚

u 实例意外中断的未决事务回滚

u 恢复过程中没有完成的事务的回滚

如果不指向任何保存点(savepoint)回滚整个事务,会发生:

1、 Oracle使用相关undo表空间来撤销所有SQL语句造成的改变

2、 Oracle释放所有数据锁

3、 结束事务。

事务保存点

你可以在事务环境中标识叫做保存点的中间标志。保存点(savepoint)将一个长事务分成多个小部分。

使用保存点,你可以在一个长事务中在任意点标识你的工作。这样你可以选择回滚事务中当前检查点之前的工作,或者检查点之后的工作。例如,你可以在执行一系列长的复杂的更新时使用检查点,所以如果你遇到了一个错误,你不需要重新执行所有的语句。

在应用程序开发中保存点也非常有用。如果一个过程包含多个函数,然后你可以在每个函数开始前设置一个保存点。这样如果一个函数失败了,你很容易将数据返回到函数执行前的状态并用不同的参数来执行函数,或者你可以执行一个恢复动作。

回滚一个检查点之后,Oracle会释放回滚语句获得的数据锁。其他等待锁定资源的事务就可以执行了。其他打算更新锁定行的事务也可以执行了。

当一个事务回滚到保存点,会发生:

1、 Oracle只回滚检查点之后的语句

2、 Oracle维护所有的保存点,但是指定保存点之后的所有检查点做的改变都将丢失。

3、 Oracle释放这个检查点以来所有需要的表或行锁,但是保留保存点之前需要的所有数据锁。

事务仍然保持活动并可以继续运行。

当一个会话在等待一个事务时,回滚到检查点不会释放任何行锁。如果事务没有获得锁,为确保一个事务没有挂起,在UPDATE和DELETE语句前执行FOR UPDATE ……NOWAIT。(这个指向已经回滚的保存点之前获得的锁。保存点之后的获得的锁都被释放了,因为保存点之后执行的语句都被完全回滚。)

事务命名

你可以使用一个简单的容易记忆的文本字符串命名一个事务。名字提示了事务是做什么的。事务命名代替了分布式事务的提交备注,包含下列优点:

u 很容易监控长时间运行的事务和解决有问题的分布式事务

u 你可以在应用程序中和事务ID一起显示事务名称。例如,在监控系统活动时,数据库管理员可以在企业管理器中显示事务名称。

u 事务名称写入到事务审核重做记录中,兼容Oracle9i或更高版本

u LogMiner可以使用事务名称在重做日志中搜索特定的事务审核记录

u 你可以在数据字典视图中使用事务名查找特定的事务,如V$TRANSACTION

事务如何命名

在启动事务之前,使用SET TRANSACTION … NAME语句来命名事务。

当你命名一个事务时,你同时将事务名称和ID做了关联。事务名称并不需要保证唯一。同一个用户同时可以拥有同名的不同事务。你可以使用任何名称来分辨不同的事务。

提交事务

在以前的发布版本中,你可以使用提交备注来对事务进行关联。虽然如此,一个备注只有在事务提交时才会关联索引。

提交备注在后续版本中仍然支持。虽然如此,Oracle强烈建议你使用事务名称。提交备注在命名事务中会被忽略。

两步提交机制

在分布式数据库中,Oracle必须跨网络协调事务控制以及维护数据完整性。即使在网络或系统故障的情况下也要做到。

分布式事务指的是包含在分布式数据库上两个或多个节点上运行的一个或多个更新数据的语句的事务。

两步提交确保了参与一个分布式事务的所有数据库服务器的事务完全失败或者完全成功。两步提交机制还保护了完整性约束隐含的DML操作、远程过程调用和触发器等。

Oracle的两步提交机制对使用分布式事务的用户来说是完全透明的。事实上,用户甚至不需要知道事务是分布式的。COMMIT语句标识了事务的结束,并自动启动两步提交机制来提交事务。在数据库应用程序中不需要为包含的分布式事务进行额外的编码或者复杂的语法定义。

后台恢复进程(RECO)自动解决有问题的分布式事务,这些问题事务指的是由于任何原因的系统或网络故障导致的提交失败。当故障被修复,通讯重新建立时,每个本地Oracle数据库的RECO进程自动提交和回滚问题进程,从而保证相关节点的一致性。

在长期的故障中,Oracle允许每个本地管理员手工提交或者回滚任何由于故障导致的有问题的分布式事务。这个选项使得本地数据库管理员可以释放任何由于长时间故障而造成的锁。

如果一个数据库必须恢复到过去的一个时间点,Oracle恢复工具可以让其他站点的数据库管理员也恢复他们的数据库到同一的时间点。这个操作确保了整体数据库的一致性。

自治事务概述

自治事务是指在一个事务内部调用的独立事务。一个自治事务可以让你离开调用事务的环境、执行一些SQL操作、提交或者撤销这些操作,然后返回到调用事务的环境,然后继续执行这个事务。

只要开始执行,一个自治事务就完全独立于调用它的主事务。它看不到主事务的任何未提交的改变、不和注事务共享任何锁和资源。自治事务产生的改变在自身的提交之后就可以让其他事务看到。

一个自治事务可以调用另一个自治事务。只要有足够的资源,可以调用任意层次的自治事务。

在自治事务和它的调用事务之间可能产生死锁。Oracle可以检测到这个死锁,并返回一个错误。应用开发人员负责避免死锁出现。

自治事务在实现需要独立执行的动作时非常有用,自治事务会忽略调用事务的提交或者回滚的操作,比如事务日志和重新计数这种情况。

自治PL/SQL块

你可以在PL/SQL块中调用自治事务,使用标记AUTONOMOUS_TRANSACTION。一个标记可以直接编译。你可以指定下列类型的PL/SQL块为自治事务:

u 存储过程或函数

u 本地过程和函数

u 包

u 类型方法

u 自治事务块的上层

当一个自治PL/SQL块执行时,调用者的事务环境就被暂停了。这个操作确保这个块执行的SQL操作不依赖且不影响调用者事务环境的状态。

当一个自治块执行另一个自治事务块或者其本身时,被调用块并不和调用块共享任何事物环境。虽然如此,当一个自治块执行一个非自治块时(就是说一个没有声明为自治事务),被调用块继承了调用事务块的事务环境。

自治事务块中的事务控制语句

自治PL/SQL块中的事务控制语句只在当前活动的自治事务中起作用。下列语句:

SET TRANSACTION

COMMIT

ROLLBACK

SAVEPOINT

ROLLBACK TO SAVEPOINT

类似的,主事务中的事务控制语句只对本事务有效,不影响任何它调用的自治事务。例如,将主事务回滚到自治事务开始之前的保存点(savepoint)并不会撤销自治事务。