5.3 事务处理

  事务(Transaction)是数据库中一个非常重要的概念,作为软件开发人员,在用程序操作数据库时,常用到事务。事务的主要任务是确保数据的一致性,使程序员可以更加灵活地执行对数据库的操作,避免数据库中出现数据错误。

  事务由一组DML语句组成,完成一个相对完整的功能。例如,当一个银行客户从一个活期卡账户转账一定的数额形成一个定期账户时,这对于数据库而言就是一个事务。该事务由三部分单独的操作组成,减少活期账户余额,创建定期账户和记录交易信息。作为数据库,必须保证组成事务的三部分操作全部完成,才能维护数据的一致性。当因为某种原因,导致其中的一个操作失败时,其他的操作也会被撤销。

5.3.1 事务分类

  SQL语言按其功能分为四大类:数据查询语言DQL、数据操纵语言DML、数据定义语言DDL、数据控制语言DCL。事务是为了保持数据的一致性,而数据查询语言只是从数据库中查询数据,不会引起一致性问题。所以,根据SQL语言的分类情况,可以将事务分为针对DML的事务、针对DDL的事务和针对DCL的事务。

  当执行第一个DML SQL语句时或一个事务结束之后下一个SQL语句开始时,事务开始。当碰到一个COMMIT(提交)语句或ROLLBACK(回滚)语句时,事务结束。尤其需要注意的是,DDL语句(例如创建表)和DCL语句(例如给用户授权)执行时自动提交事务,不需要显式提交,在此之前的DML语句也一并被隐式提交。另外,在数据库客户端程序退出或者数据库崩溃时,为了保持数据一致性,也会结束事务。

5.3.2 事务控制

  下面列举了事务控制语句,如表5.1所示。

表5.1 事务控制语句

语 句 说 明
COMMIT 提交当前事务,使之前做的改变永久作用于数据库
ROLLBACK 回滚当前事务,丢弃所有未决的数据改变
SAVEPOINT name 在当前事务中标记保存点(非ANSI SQL标准)
ROLLBACK TO name 回滚当前事务到指定的保存点从而丢弃保存点后对数据库的任何改变
  • COMMIT和ROLLBACK语句

  接下来演示一下COMMIT和ROLLBACK的使用。假设需要删除雇员编号为209的雇员,执行下面的SQL语句:

  1. DELETE FROM employees WHERE employee_id = 209

  在新SQL窗口中执行如下的SQL语句进行查询,其结果如图5.8所示。

  1. SELECT employee_id, last_name,salary FROM employees WHERE employee_id = 209

5.3 事务处理 - 图1


图5.8 事务控制

  此时,删除操作并没有永久作用于数据库,可以使用ROLLBACK语句回滚整个事务,撤销该删除操作,或使用COMMIT语句提交事务,让删除操作永久作用于数据库。在原SQL窗口中,先执行回滚,再执行提交,其SQL语句如下:

  1. ROLLBACK;
  2. COMMIT;

  在新SQL窗口中,再次在雇员表中查询雇员编号为209的雇员信息,仍然可以查到该雇员信息。原因是先回滚,再提交,删除操作已被取消,编号为209的雇员仍在数据库中。

  另外,还有一种情况,就是出现了客户端工具意外退出的情况或发生系统故障,此时整个事务会被自动回滚。该回滚防止不必要的数据改变错误发生,保证Oracle数据的完整性。

  执行DML语句且没有结束事务时,如果需要查询数据库的真实改变情况,则要求在一个新SQL窗口中执行查询语句。为什么这样呢?

  因为事务中所做的每一个操作在事务被提交之前都是临时的,在COMMIT或ROLLBACK语句执行之前,DML语句首先影响该用户的数据库缓冲区,因此这些操作可以被恢复,而且因为是在该用户的数据缓冲区,所以在原SQL窗口中查询得到的是数据缓冲区的结果,不是数据库真实的数据。要想拿到数据库真实的数据,需要在新SQL窗口中执行查询语句。这样,针对不同的用户,Oracle服务器用读一致性来确保每个用户看到的数据和上次提交时的数据相同。

  另外,在一个用户执行DML语句(未结束事务)影响数据库中相关的行时,受影响的行被锁定,其他用户不能改变受影响的行中的数据,直到事务结束时为止。

  假设现在雇员表中还存在雇员编号为209的这个雇员信息,执行下面的SQL语句,目的是删除编号为209的雇员记录。

  1. DELETE FROM employees WHERE employee_id = 209

  此时在一个新SQL窗口中执行如下的SQL语句,用于更改雇员编号为209的雇员的薪水。

  1. UPDATE employees SET salary = 10000 WHERE employee_id = 209

  PL/SQL Dev执行时的结果:显示该语句一直在执行,但始终没有执行结果。这就说明了该行数据已被锁定,其他用户不能改变该行中的数据。

  在原窗口中执行COMMIT语句,提交当前事务,使删除操作永久作用于数据库。此时,新SQL窗口立刻显示0行记录被更新,说明该行已被解锁,且因为已被删除,故没有数据被更新。

  • SAVEPOINT语句

  在当前事务中用SAVEPOINT name语句创建一个标记,该标记称为保存点标记,它可以把事务分成更小的部分,使用ROLLBACK TO name语句,丢弃保存点之后的所有未决的数据改变。其语法形式如下:

  1. DML A
  2. SAVEPOINT sp;
  3. DML B
  4. ROLLBACK TO sp;

  当执行ROLLBACK TO sp语句时,DML B段的操作将会被撤销。