4.3 事务
结束事务
系统出现不一致例子
银行例子
大学应用例子
原子性
不是commit或Rollback的命令出错时是提交还是回滚得看具体的数据库实现
默认一条`SQL`语句一个事务
关闭自动提交 一个事务执行多条SQL
后续章节对事务的介绍
4.3 事务
事务(transaction
)由查询询和(或)更新语句的序列组成
。**SQL
标准规定当一条SOL
语句被执行,就隐式地开始了一个事务**。
结束事务
下列SQL
语句之一会结束一个事务:
Commit work
:提交当前事务,也就是将该事务所做的更新在数据库中持久保存。在事务被提交后,一个新的事务自动开始。Rollback work
:回滚当前事务,即撤销该事务中所有SoL
语句对数据库的更新。这样,数据库就恢复到执行该事务第一条语句之前的状态。
关键词work
在两条语句中都是可选的
当在事务执行过程中检测到错误时,事务回滚是有用的。在某种意义上,事务提交就像对编辑文档的变化存盘,而回滚就像不保存变化退出编辑。一旦某事务执行了commit work,
它的影响就不能用rollback work
来撤销了。
数据库系统保证在发生诸如某条SQL
语句错误、断电、系统崩溃这些故障的情况下,如果一个事务还没有完成commit work
,其影响将被回滚。
在断电和系统崩溃的情况下,回滚会在系统重启后执行。
系统出现不一致例子
银行例子
例如,考虑一个银行应用,我们需要从一个银行账户上把钱转到同一家银行的另一个账户。为了这样做,我们需要更新两个账户的余额,把需要转移的资金额从一个账户划走,并把它加到另一个账户上。如果在从第一个账户上划走资金以后,但在把这笔资金加入第二个账户之前发生了系统崩溃,那么银行账户就会不一致。如果在第一个账户划走资金之前先往第二个账户存款,并且在存款之后马上发生系统崩溃,那么也会出现类似的问题。
大学应用例子
作为另一个例子,考虑我们正在使用的大学应用的例子。我们假设student
关系中每个元组在tot_cred
属性上的取值需要保持在最新状态,只要学生成功修完一门课程,该属性值就要更新。为了这样做只要takes
关系被更新为记录一位学生成功修完一门课程的信息(通过赋予适当的成绩),相应的student
元组也必须更新。如果执行这两个更新的任务在执行完一个更新后,但在第二个更新前崩溃了,数据库中的数据就是不一致的。
原子性
一个事务
- 或者在完成所有步骤后提交其行为,
- 或者在不能成功完成其所有动作的情况下回滚其所有动作,
通过这种方式数据库提供了对事务具有原子性(atomic
)的抽象,原子性也就是不可分割性,
- 要么事务的所有影响被反映到数据库中,
- 要么任何影响都没有(在回滚之后)。
如果把事务的概念应用到上述应用中,那些更新语句就会作为单个事务执行。在事务执行其某条语句时出错会导致事务早先执行的语句的影响被撒销,从而不会让数据库处于部分更新状态。
不是commit或Rollback的命令出错时是提交还是回滚得看具体的数据库实现
如果程序没有执行Commit
或Rollback
两条命令中的任何一条而终止了,那么更新要么被提交要么被回滚。SQL
标准并没有指出究竟执行哪一种,如何选择依赖于具体实现。
默认一条SQL
语句一个事务
在很多SQL
实现中,默认方式下每个SQL
语句自成一个事务
,且一执行完就提交。
关闭自动提交 一个事务执行多条SQL
如果一个事务要执行多条SQL
语句,就必须关闭单独SQL
语句的自动提交。如何关闭自动提交也依赖于特定的SQL
实现,尽管在诸如JDBC
或ODBC
那样的应用编程接口中存在标准化方式来完成这项工作。我们将在5.1.1
和5.1.2
节分别学习JDBC
和ODBC
。
一个较好的选择是,作为SQL:1999
标准的一部分(但目前只有一些SQL
实现支持),允许多条SQL
语句包含在关键字begin atomic … end
之间。所有在关键字之间的语句构成了一个单一事务。
后续章节对事务的介绍
- 我们将在第
14
章学习事务的更多特性; - 第
15
章和第16
章介绍在单个数据库中实现事务的相关问题, - 而在第
19
章介绍跨多个数据库上实现事务的相关问题,这是为了处理不同银行的账户之间转账的问题,不同银行有不同的数据库。