Oracle从新手到高手
上QQ阅读APP看书,第一时间看更新

4.5 Oracle中的事务处理

在Oracle系统中,在使用INSERT、UPDATE和DELETE语句操作数据时,数据库中的数据并不会立即改变,用户还可以通过控制事务确认是否提交或取消先前的操作。

4.5.1 事务的基本概念

事务是数据库系统工作的一个逻辑单元,它由一个或多个SQL语句组成。对于数据库而言,事务是不可分割的工作单元,一个事务中的所有SQL语句要么全部执行,要么全部不执行。也就是说,当事务被提交后,该事务中的操作才真正被保存到数据库中。如果某个事务被回退了,那么该事务中的所有操作都被取消。事务的回退和提交可以由用户显式执行,也可以隐式地执行。

一般情况下,用户或应用程序需要显式地执行COMMIT语句提交事务,但是用户也可以不使用COMMIT语句而隐式地提交事务。例如,在事务的结尾处使用DDL语句时,Oracle默认为提交当前的事务,并且开始一个新的事务。只有当事务被提交后,其他用户才能够看到对数据库的修改结果。下面将启动两个SQL*Plus会话来演示Oracle的事务处理特性。

① 启动SQL*Plus,使用SCOTT身份连接数据库,并且向EMP表添加一些数据,如下所示。

② 在该会话中执行如下的查询时,用户可以看到先前插入的数据。

③ 现在打开另一个SQL*Plus,并且保持第一个SQL*Plus不被关闭。在第二个SQL*Plus中执行相同的SELECT语句,以查看先前插入的数据。

在这里可以发现,由于第一个会话没有提交事务,所以在第二个会话中看不到第一个会话添加数据。

④ 在第一个SQL*Plus中使用COMMIT语句提交事务。

      SQL> commit;
      提交完成。

⑤ 现在,如果用户再次在第二个SQL*Plus中运行上面的SELECT语句,就会看到在第一个SQL*Plus中所提交的数据。

4.5.2 事务控制

Oracle中的事务是隐式自动开始的,它不需要用户显式地使用语句开始事务处理。当发生如下情况时,Oracle认为一个事务结束。

※ 执行COMMIT语句提交事务。

※ 执行ROLLBACK语句撤销事务。

※ 执行一条数据定义语句(如CREAE、DROP或ALTER语句等)。如果该语句执行成功,那么表示系统自动执行COMMIT命令;如果这种操作失败,那么表示系统自动执行ROLLBACK命令。

※ 执行一个数据控制命令(如GRANT、REVOKE等),这种操作表示自动执行COMMIT命令。

※ 断开数据库的连接。如果使用EXIT命令正常退出SQL*Plus,则系统自动执行COMMIT命令;如果退出SQL*Plus出现异常,则系统自动执行ROLLBACK命令。

下面主要介绍通过ROLLBACK语句控制事务。

1. 使用COMMIT语句提交事务

提交事务也就意味着该事务中对数据库进行的全部操作将永久地记录在数据库中。在使用COMMIT提交事务时,Oracle会执行如下操作。

① 在回退段内记录事务已经提交,并且生成一个唯一的系统变改号(SCN),以唯一标识这个事务。

② 启动LGWR后台进程,将SGA区中的重做日志缓存中的数据写入联机重做日志文件中,并且将该事务的SCN也保存到联机重做日志文件中。

③ Oracle服务器进程释放事务处理所占用的资源。

④ 通知用户事务已经成功提交。

需要注意,Oracle提交事务的性能不会因为事务所包含的SQL语句过多而受到影响,因为Oracle采用了一种称为“快速提交”(Fast Commit)的机制,当用户提交事务时,Oracle并不会将与该事务相关的“脏数据块”立即写入数据文件,只是将相应的日志信息保存到重做日志文件,这样即使发生错误丢失了内存中的数据,系统还可以根据重做日志文件中的信息对其进行还原。因此,只要事务的重做日志信息被完全写入联机重做日志文件中,即可认为该事务已经成功提交。

2. 回退事务

回退一个事务也就意味着在该事务中对数据库进行的全部操作将被取消,Oracle利用回退段(或撤销表空间)来存储修改前的数据,通过重做日志来记录对数据所做的修改。如果要回退整个事务,Oracle将会执行如下操作。

① 使用回退段中的数据撤销事务中所有SQL语句对数据库所做的修改。

② Oracle服务进程释放事务所占用的资源。

③ 通知用户事务回退成功。

Oracle不仅允许回退整个未提交的事务,还允许回退事务的一部分,这是通过一种称为“保存点”的机制实现的。在事务的执行过程中,用户可以通过建立保存点将一个较长的事务分隔为几部分。这样用户就可以有选择性地回退到某个保存点,而保存点之后的操作都将被取消。

在下面的示例,将向SCOTT模式中的EMP表添加两行记录,并且在执行第一条INSERT语句后建立一个保存点,在第二条INSERT语句后查询当前事务对数据库所做的操作。随后回退事务到保存点,以撤销第二条INSERT语句所执行的操作。