事务的基本概念
事务
事务:是一系列的数据库操作,是数据库应用程序的逻辑单位,即应用程序对数据库的操作都应该以事务的方式进行。
事务是一个操作序列,这些操作“要么都做,要么都不做”。
事务定义的语句如下:
BEGIN TRANSACTION
:事务开始。END TRANSACTION
:事务结束。COMMIT
:事务提交。该操作表示事务成功地结束,它将通知事务管理器该事务的所有更新操作现在可以被提交或永久地保留。ROLLBACK
:事务回滚。该操作表示事务非成功地结束,它将通知事务管理器出故障了,数据库可能处于不一致状态,该事务的所有更新操作必须回滚或撤销。
例:从账户 A 转入账户 B 金额 x 元。
BEGIN TRANSACTION -- 事务开始 read(A); -- 读账户A的余额 A = A - x; -- A账户金额减去x元 IF(A < 0) THEN print (“ 金额不足,不能转账 ”); ROLLBACK; -- 撤销该事务 , 回到事务执行前的状态 ELSE write(A); -- 写入账户A的余额 read(B); -- 读账户B的余额 B = B + x; write(B); COMMIT; -- 提交事务 END IF; END TRANSACTION -- 事务结束
SQL 中事务的开始与结束
SQL 标准规定当一条 SQL 语句被执行,就隐式地开始了一个事务,SQL 中的 Commit work
和 Rollback work
语句之一会结束一个事务。
Commit work
:提交当前事务。这意味着该事务所做的更新在数据库中永久保存。一但事务被提交后,一个新的事务自动开始。-
Rollback work
:回滚当前事务。这意味着将撤销该事务对数据库的更新。
注意:如果事务已经执行了 Commit work
,就不能再用 Rollback
来撤销。
事务的特性
事务具4个特性:原子性、一致性、隔离性和持久性。
- 原子性:事务的所有操作在数据库中要么都做要么都不做。
- 一致性:一个事务独立执行的结果,将保持数据的一致性,即数据不会因为事务的执行而遭受破坏。
- 隔离性:一个事务的执行不能被其他事务干扰。并发事务在执行过程中可能会对同一数据进行操作,这些事务的操作应该不会相互干扰,是相互隔离的。
- 持久性:一个事务一旦提交,它对数据库的改变必须是永久的,即使系统出现故障也是如此
事务的状态
事务是数据库的基本执行单元,如果事务成功执行,则数据库从一个一致状态进入另一个一致状态。如果因为某种原因事务没能成功执行,但其已经对数据库进行了修改,这时候可能会导致数据库处于不一致的状态,需要对事务已经造成的变更进行撤销(回滚)。
- 活动状态:事务的初始状态,事务执行时处于这个状态。
- 部分提交状态:当操作序列的最后一条语句执行后,事务就处于部分提交状态。 这时,事务虽然已经完全执行,但由于实际输出可能还临时驻留在内存中,在事务成功完成前还有可能出现硬件故障,因此,部分提交状态并不等于事务成功执行。
- 失败状态:由于硬件或逻辑错误,使得事务不能继续正常执行,事务就进入了失败状态,处于失败状态的事务必须回滚。这样,事务就进入了中止状态。
- 中止状态:事务回滚并且数据库恢复到事务开始执行前的状态。
- 提交状态:当事务成功完成后,称事务处于提交状态。只有事务处于提交状 后,才能说事务已经提交。
事务的状态转换:
BEGIN TRANSACTION
:开始运行事务,使事务进入活动状态END TRANSACTION
:说明事物中的所有读写操作都已完成,使事务进入部分提交状态,把事务的所有操作对数据库的影响存入数据库。COMMIT
:标志事务已经成功地完成,事务中的所有操作对数据库的影响已经安全地存入数据库,事务进入提交状态,结束事务的运行。ABORT
:标志事务进入失败状态,系统撤销事务中所有操作对数据库和其他事务的影响,结束事务的运行。
数据库的并发控制
事务调度
串行调度
是指多个事务依次串行执行,且只有当一个事务的所有操作都执行完成才执行另一个事务的所有操作。
例:有两个事务 T0 和 T1,事务 T0 从账号 A 转 2000 元到账号 B;事务 T1 从账号 A 转 20% 的款到账号 B。T0 和 T1 的定义如下所示。
并发调度
利用分时的方法同时处理多个事务。
可恢复调度
指满足这样的条件的调度:当事务 T~j~ 要读事务 T~i~ 写的数据时,T~i~ 事务必须要先于事务 T~j~ 提交。
某银行信息系统有两项业务对应的事务 T1、T2 与存款关系有关。其中,转账业务:T1(A,B,50), 从账户 A 向账户 B 转 50 元;计息业务:T2,对当前所有账户的余额计算利息,余额为 X*1.01。针对上述业务流程,回答下列问题:
- 若当前账户 A 余额为 100 元,账户 B 余额为 200 元。有两个事务分别为 T1(A, B, 50),T2。可能的串行执行为:T1→T2 或 T2→T1,请计算串行执行结果。
- 若上述两个事务的一个并发调度顺序如下图所示,请问调度是否正确,为什么?
并发操作带来的问题
并发操作带来的数据不一致性有三类:丢失修改、不可重复读和读脏数据。
丢失修改
两个事务对同一个数据进行修改,导致事务A对数据库的 修改被事务B的修改所覆盖。
不可重复读
事务对同一数据进行两次读取的结果不同。原因是两 次读取的间隙数据被另一事务修改了。
读脏数据
某事务读取的数据是其它事务修改后的值,但该修改后 来又被撤销了。
并发调度的可串行性
多个事务的并发执行是正确的,当且仅当其结果与某一次序串行地执行它们的结果相同,称这种调度策略是可串行化的调度。
可串行性是并发事务正确性的准则。即:一个给定的并发调度,当且仅当它是可串行化的才认为是正确调度。
并发控制技术
并发事务如果对数据读写时不加以控制,会破坏事务的隔离性和一致性。为了保持事务的隔离性,系统必须对事务之间的相互作用加以控制,最典型的方式就是加锁。
- 排它锁(Exclusive Locks, 简称 X 锁):也称为写锁,用于对数据进行写操作时进行锁定。如果事务 T 对数据 A 加上 X 锁后,就只允许事务 T 对数据 A 进行读取和修改,其他事务对数据 A 不能再加任何锁, 也不能读取和修改数据 A,直到事务 T 释放 A 上的锁。
- 共享锁(Share Locks, 简称 S 锁):也称为读锁,用于对数据进行读操作时进行锁定。如果事务 T 对数据 A 加上了 S 锁后,事务 T 就只能读数据 A 但不可以修改,其他事务可以再对数据 A 加 S 锁来读取, 只要数据 A 上有了 S 锁,任何事务都只能再对其加 S 锁读取而不能加 X 锁修改。
封锁协议
- 一级封锁协议:是指事务 T 在修改数据 A 之前必须先对其加 X 锁,直 到事务结束才释放 X 锁。解决了丢失修改的问题。
- 二级封锁协议:是一级封锁协议加上事务 T 在读取数据 A 之前必须对其加上 S 锁,读完后即可释放 S 锁。解决了读脏数据的问题。
- 三级封锁协议:是一级封锁协议加上事务 T 在读取数据 A 之前必须对其加上 S 锁,直到事务结束才释放 S 锁。解决了不可重复读的问题。
封锁协议 | 要求 | 可解决 |
---|---|---|
一级封锁协议 | 修改前加X锁,事务结束后释放 | 丢失修改 |
二级封锁协议 | 在一级之上再规定:读取前加S锁,读完后释放 | 丢失修改、读脏 |
三级封锁协议 | 在一级之上再规定:读取前加S锁,事务结束后释放 | 丢失修改、读脏,不可重复读 |
两段锁协议
两段锁协议(2PL):是指同一事务对任何数据进行读写之前必须对该数据加锁; 在释放一个封锁之后,该事务不再申请和获得任何其他封锁。
所谓“两段”的含义是:事务分为两个阶段。第一阶段是获得封锁,也称为扩展阶段。第二阶段是释放封锁,也称为收缩阶段。
T1:Slock A…Slock B…Xlock C…Unlock B…Unlock A…Unlock C
T2:Slock A…Unlock A…Slock B…Xlock C…Unlock C…Unlock B
如果事务遵循两段锁协议,那么它们的并发调度是可串行化的。两段锁是可串行化的充分条件,但不是必要条件。即:遵循两段锁协议,一定是可串行化的;不遵循两段锁协议,可能是可串行化的,也可能不是。
注意:采用两段锁协议也有可能产生死锁,这是因为每个事务都不能及时解除被封锁的数据,可能会导致多个事务都要求对方已经封锁的数据而不能继续运行。
事务的隔离级别
READ UNCOMMITTED
(读未提交):可避免丢失修改。READ COMMITTED
(读已提交):可避免丢失修改、读脏数据。REPEATABLE READ
(可重复读):可避免丢失修改、读脏数据,不可重复读。SERIALIZABLE
(串行化):最高级别,可避免丢失修改、读脏数据、不可重复读、幻读。
幻读:事务 A 查询得到 N 条数据,然后事务 B 又插入了 M 条数据,或者改变了这 N 条数 据之外的 M 条符合事务 A 搜索条件的数据,导致事务 A 再次搜索发现有 N+M 条数据了, 就产生了幻读。
某航空售票系统负责所有本地起飞航班的机票销售业务,并设有多个机票销售网点。各售票网点使用相同的售票程序。 假设系统有如下业务及规则。
- 售票程序中用到的伪指令如表 11-2 所示。
伪指令 说明 R(A, x) 返回航班A当前的剩余机票数给变量x W(A, x) 将当前数据库中航班A的剩余机票数设置为变量x的值
- 若某售票网点一次售出 a 张航班 A 的机票,则售票程序的伪指令序列为:R (A, X);W (A, x-a)。
根据上述业务及规则,完成下列问题。
【问题 1】假设有两个售票网点同时销售航班 A 的机票,那么在数据库服务器端可能出现如下的调度:
A:R1(A, x),R2(A, x),W1(A, x-1),W2(A, x-2); B:R1(A, x),R2(A, x),W2(A, x-2),W1(A, x-1); C:R1(A, x),W1(A, x-1),R2(A, x),W2(A, x-2);
其中 Ri (A, x),Wi (A, x) 分别表示第 i 个销售网点的读写操作,其余类同。 假设当前航班 A 剩余 10 张机票,请分析上述三个调度各自执行完后的剩余票数,并指出错误的调度及产生错误的原因。
【问题 2】
- 判定事务并发执行正确性的准则是什么?如何保证并发事务正确地执行?
- 采用相应的加锁、解锁指令,重写售票程序的伪指令序列,以保证正确的并发调度。
数据库的备份与恢复
数据库系统故障的种类
事务故障
是由于程序执行错误而引起事务非预期的、异常终止的故障。
通常有如下两类错误引起事务执行失败:
- 逻辑错误。如非法输入、找不到数据、溢出、超出资源限制等原 因引起的事务执行失败。
- 系统错误。系统进入一种不良状态(如死锁),导致事务无法继续执行。
系统故障
是指硬件故障、软件(如DBMS、OS或应用程序)漏洞的影响,导致丢失了内存中的信息,影响正在执行的事务,但未破坏存储在外存上的信息。
介质故障
是指数据库的存储介质发生故障,如磁盘损坏、瞬间强 磁场干扰等。这种故障直接破坏了数据库,会影响到所有正在读取这部 分数据的事务。
数据库备份
数据转储是将数据库自制到另一个磁盘或磁带上保存起来的过程,又称为数据备份。
- 静态转储和动态转储。静态转储是指在转储期间不允许对数据库进行任何存取、修改操作;动态转储是在转储期间允许对数据库进行存取、修改操作,因此, 转储和用户事务可并发执行。
- 海量转储和增量转储。海量转储是指每次转储全部数据;增量转储是指每次只转储上次转储后更新过的数据。
- 日志文件。在事务处理的过程中,DBMS 把事务开始、事务结束以及对数据库的插入、删除和修改的每一次操作写入日志文件。
- 数据库镜像。为了避免磁盘介质出现故障影响数据库的可用性,许多 DBMS 提供数据库镜像功能用于数据库恢复。
数据库恢复
要使数据库在发生故障后能够恢复,必须建立冗余数据,在故障发生后利用这些冗余数据实施数据
库恢笔,常用的是数据转储和日志文件。
故障恢复的两个操作
- 撤销事务 (UNDO):将未完成的事务撤销,使数据库恢复到事务执行前的正确状态。
撤销事务的过程:反向扫描日志文件(由后向前扫描),查找事务的更新操作;对该事务的更新操作执行逆操作,用日志文件记录中更新前的值写入数据库,插入的记录从数据库中删除,删除的记录重新插入数据库中;继续反向扫描日志文件,查找该事务的其它更新操作并执行逆操作直至事务开始标志。 - 重做事务 (REDO):将已提交的事务重新执行。
重做事务的过程:从事务的开始标志起,正向扫描日志文件,重新执行日志文件登记的该事务对数据库的所有操作,直至事务结束标识
故障恢复策略
事务故障的恢复
事务故障是事务在运行至正常终止点(SUMMIT 或 ROLLBACK)前终止,日志文件只有该事务的开始标识而没有结束标识。对这类故障的恢复通常是通过撤销(UNDO)产生故障的事务,使数据库恢复到该事务执行前的正确状态来完成的。
具体做法:
- 反向扫描日志文件,查找该事务的更新操作。
- 对事务的更新操作执行逆操作。
- 继续反向扫描日志文件,查找该事务的其他更新操作,并做同样的处理,直到事务的开始标志。
注:事务故障的恢复是由系统自动完成的,对用户是透明的。
系统故障的恢复
系统故障会使数据库的数据不一致:
一是未完成的事务对数据库的更新可能已经写入数据库;
二是已提交的事务对数据库的更新可能还在缓冲区没来得及写入数据库。
因此对于系统故障,恢复操作是 UNDO+REDO:
- 撤销故障发生时未完成的事务(UNDO)。
- 重做已经提交的事务(REDO)。
介质故障的恢复
介质故障时数据库遭到破坏,需要重装数据库,一般需要 DBA 的参与,装载故障前最近一次的备份和故障前的日志文件副本,再按照系统故障的恢复过程执行撤销(UNDO)和重做(REDO)来恢复。
检查点机制(CHECKPOINT):在日志中设置检查点,当发生故障需要利用日志文件恢复时,反向扫描日志文件,找到检查点,确认检查点时刻正在执行的事务(活动事务),即检查点前有事务开始标志但没有事务结束标志。
对于检查点后提交的事务,执行 REDO(重做)
对于检查点后未提交的事务,执行 UNDO(撤销)
【说明】
如果一个数据库恢复系统采用检查点机制,且其日志文件如表 5-1 所示,第一列表示日志记录编号,第二列表示日志记录内容,<Ti,START> 表示事务 Ti 开始执行,<Ti,COMMIT > 表示事务 Ti 提交,<Ti,D,V1,V2 > 表示事务 Ti 将数据项 D 的值由 V1 修改为 V2,
请回答以下问题。
【问题 1】(6 分)
假设系统开始执行前 X=100, Y=50, Z=10,系统出错恢复后,X,Y,Z 各自的数值是多少?
【问题 2】(4 分)
系统发生事务故障时,故障恢复有撤销事务(UNDO)和重做事务(REDO)两个操作,
请给出系统恢复时需要 REDO 的事务列表和需要 UNDO 的事务列表。
【问题 3】(5 分)
请简要描述系统出错后,基于检查点的恢复过程。