6.2 控制事务
SQL入门经典(第5版)
事务控制是对关系型数据库管理系统(RDBMS)里可能发生的各种事务的管理能力。在谈及事务时,我们是指前一章所介绍的INSERT、UPDATE和DELETE命令。
by注意:
事务的启动或执行在各个实现中是不同的,详细情况请查看具体实现的文档。
当一个事务被执行并成功完成时,虽然从输出结果来看目标表已经被修改了,但实际上目标表并不是立即被修改。当事务成功完成时,利用事务控制命令最终认可这个事务,可以把事务所做的修改保存到数据库,也可以撤销事务所做的修改。
控制事务的命令有3个:
COMMIT;
ROLLBACK;
SAVEPOINT。
下面的小节将详细介绍这3个命令。
by注意:什么时候可以使用事务
事务控制命令只与DML命令INSERT、UPDATE和DELETE配合使用,比如我们不会在创建表之后使用COMMIT语句,因为当表被创建之后,它会自动被提交给数据库。也不能使用ROLLBACK语句来恢复被撤销的表。此外,还有其他类似的语句,也是不能被撤销的,例如TRUNCATE语句。所以,在运行新的命令前,最好先确认一下用户所使用的RDBMS在事务方面的相关规定。
当事务完成之后,事务信息被保存在数据库里的指定区域或临时回退区域。所有的修改都被保存到这个临时回退区域,直到事务控制命令出现。当事务控制命令出现时,所做的修改要么被保存到数据库,要么被放弃,然后临时回退区域被清空。图6.1展示了修改操作如何应用到关系型数据库。
6.2.1 COMMIT命令
COMMIT命令用于把事务所做的修改保存到数据库,它把上一个COMMIT或ROLLBACK命令之后的全部事务都保存到数据库。
这个命令的语法是:
关键字COMMIT是语法中唯一不可缺少的部分,其后是用于终止语句的字符或命令,具体内容取决于不同的实现。关键字WORK是个选项,其唯一作用是让命令对用户更加友好。
在下面这个范例里,我们首先从查询表PRODUCT_TMP里的全部数据开始:
接下来,删除表里所有价格低于$14.00的产品。
使用一个COMMIT语句把修改保存到数据库,完成这个事务。
对于数据库的大规模数据加载或撤销来说,应该多使用COMMIT语句;然而,过多的COMMIT语句会让工作需要大量额外时间才能完成。记住,全部修改都首先被送到临时回退区域,如果这个临时回退区域没有空间了,不能保存对数据库所做的修改,数据库很可能会挂起,禁止进一步的事务操作。
实际上,在提交了一条UPDATE、INSERT或DELETE语句之后,大部分RDBMS都是使用事务来进行后台处理的,一旦操作被取消或报错,所做的操作就可以被撤销。所以,在提交了一个事务之后,会有一系列操作来确保事务正常运行。在现实生活中,用户可能会在ATM上提交一个银行事务以便从自己的账户中取出现金。这时,就需要完成取钱和更新账户余额两项事务。很显然,我们希望这两项事务能够同时完成,或者全部失败。否则,系统数据的完整性就会受到影响。所以,在这个实例中,我们会将两项操作合并为一个事务,来确保对操作结果的控制。
..by.tif注意:不同的实现对COMMIT命令的提交有所不同
在某些实现里,事务不是通过使用COMMIT命令提交的,而是由退出数据库的操作引发提交。但是在其他实现里,比如MySQL,在执行SET TRANSACTION命令之后,在数据库收到COMMIT或ROLLBACK之前,自动提交功能是不会恢复的。此外,在Microsoft SQL Server中,除非事务正在运行,否则语句会被自动提交。所以,用户务必要了解所使用的RDBMS在事务处理和命令提交方面的相关规定。
6.2.2 ROLLBACK命令
ROLLBACK命令用于撤销还没有被保存到数据库的命令,它只能用于撤销上一个COMMIT或ROLLBACK命令之后的事务。
ROLLBACK的语法如下所示:
与COMMIT命令一样的是,关键字WORK只是个选项。
在下面的范例里,首先选择表PRODUCTS_TMP里的全部记录,这是前一次删除14条记录之后所剩的数据。
接下来更新表,把标识为11235的产品价格修改为$39.99:
现在对表进行一个简单的查询,可以发现修改似乎已经生效了:
现在,执行ROLLBACK命令来撤销刚刚所做的修改:
最后,验证所做的修改并没有被提交到数据库:
6.2.3 SAVEPOINT命令
保存点是事务过程中的一个逻辑点,我们可以把事务回退到这个点,而不必回退整个事务。
SAVEPOINT命令的语法如下:
这个命令就是在事务语句之间创建一个保存点。ROLLBACK命令可以撤销一组事务操作,而保存点可以将大量事务操作划分为较小的、更易于管理的组。
Microsoft SQL Server的语法稍有不同。在SQL Server中,使用的是SAVE TRANSAC- TION,而不是SAVEPOINT,范例如下:
除此之外,SQL Server与其他数据库实现完全相同。
6.2.4 ROLLBACK TO SAVEPOINT命令
回退到保存点的命令语法如下:
在下面的范例里,我们要从表PORDUCTS_TMP表里删除剩余的数据,在进行每次删除之前都使用SAVEPOINT命令,这样就可以在任何时候利用ROLLBACK命令回退到任意一个保存点,从而把适当的数据恢复到原始状态:
在相应的事务操作组里,保存点的名称必须是唯一的,但其名称可以与表或其他对象的名称相同,详细的命名规范请见具体实现的说明文档。保存点名称的设置属于个人喜好,它只被数据库开发人员用来管理事务操作组。
在三次删除操作完成之后,假设我们又改变了主意,决定回退到名为SP2的保存点。由于SP2是在第一次删除操作之后创建的,所以这样做会撤销最后两次删除操作:
现在查看表里的内容,可以发现只发生了第一次删除操作:
记住,ROLLBACK命令本身会回退到上一个COMMIT或ROLLBACK语句。由于我们还没有执行COMMIT命令,所以这时执行ROLLBACK命令会撤销全部删除命令,如下所示:
6.2.5 RELEASE SAVEPOINT命令
这个命令用于删除创建的保存点。在某个保存点被释放之后,就不能再利用ROLLBACK命令来撤销这个保存点之后的事务操作了。利用这个命令可以避免意外地回退到某个不再需要的保存点。
Microsoft SQL Server不支持RELEASE SAVEPOINT命令;在事务完成以后,所有的保存点会被自动删除。这个过程不必使用COMMIT 或者 ROLLBACK命令。用户在自己的环境中创建事务时,需要牢记这一点。
6.2.6 SET TRANSACTION命令
这个命令用于初始化数据库事务,可以指定事务的特性。举例来说,我们可以指定事务是只读的或是可以读写的,如下所示:
READ WRITE用于对数据库进行查询和操作数据的事务,READ ONLY用于只进行查询的事务。READ ONLY很适合生成报告,而且能够提高事务完成的速度。如果事务是READ WRITE类型的,数据库必须对数据库对象进行加锁,从而在多个事务同时发生时保持数据完整性。如果事务是READ ONLY,数据库就不会建立锁定,这样就会提高事务的性能。
事务还可以设置其他特性,但超出了本书的讨论范围。MySQL通过对事务实现不同级别的隔离来实现类似功能,但语法略有不同。详细情况请参考具体实现的帮助文档。