故障恢复与事务处理
事务
数据库操作序列
程序与事务:事务是程序的执行。
事务性质:ACID
原子性:全部执行。
一致性:数据库状态由 一致性状态 --> 一致性状态
隔离性:事务之间不可干扰。
持续性:事务提交,则永久改变。
PS:Git的工作区原理类似。
事务可能面临的问题
(1). 多个事务并发执行。
(2). 各类原因。
故障恢复
故障类型
(1). 事务故障。
(2). 系统故障。
故障恢复方法
(1). 数据转储
(2). 登记 (建立) 日志文件
事务的并发控制
问题(1) 的解决。
破坏一致性、隔离性:更新丢失、不可重读、脏读
封锁
封锁:事务T在对某个数据对象操作前,对系统发出请求,加锁。在事务释放锁以前,其他事务不允许更新此数据对象。
锁的类型
X锁(写锁):其他事务不可读,不可修改。(其他事务不可加任何锁)
S锁(读锁):其他事务可读,不可修改(不可加X锁)。(其他事务可以加S锁)
活锁与死锁
活锁:许多事务申请锁,T2、T3、T4。T1转给T3...
T2一直处于等待。
方法:先来先处理。
死锁:T1封锁R1,T2封锁R2。T1请求R2,T2请求R1。
方法:(1). 一次加锁法(所有要使用的数据)。(2). 顺序封锁法。
特点:与操作系统不同。诊断死锁,解除死锁。
死锁的诊断
(1). 超时法。(2). 等待图法(事务为节点,等待关系为边)。
死锁的解除
处理代价最小的事务,将其撤销,释放此事务持有的所有锁。
并发调度
调度:事务的执行次序
事务的执行方式:(1). 串行。(2). 并行。(3). 可串行化调度(并行等价于串行)
保证并发调度正确性的方法
(1) 两段锁 (Two-Phase Locking, 简称2PL) 协议
分两个阶段对数据项加锁和解锁
PS:数据可以是部分数据。依旧可能造成死锁。
说明:并行执行的所有事务均遵守两段锁协议,则对事务的所有并行调度策略都是可串行化的。
补充:两段锁协议是充分条件,不是必要条件。
(2) 时间戳协议
时间戳:事务进入系统的时间。
使用概念:
·系统时钟。 ·逻辑计数器。
·W-时间戳。成功执行W(Q)的最大时间戳****·R-时间戳。成功执行R(Q)的最大时间戳
(a) 读(当事务发出读的请求)
TS(Ti) < W-timeStamp(Q) 回滚。说明数据已经被更新了(我想要Ti时间的数据,但是这段时间被修改了)
TS(Ti) >= W-timeStamp(Q) 执行。R(Q) = max{ R(Q), TS(Ti) }(这段时间没被修改)
(b) 写(当事务发出写的请求)
TS (Ti) < R-timeStamp(Q) 回滚(解释:在TS(Ti) ~ R(Q) 间可能对数据造成更改)
PS:假设此时不回滚,意味着W会进行更新,显然不满足读的R(Q)条件
TS (Ti) < W-timeStamp(Q) 回滚(解释:写入值已经过时了)
PS:我写的值太迟了
否则:TS (Ti) >= W-timeStamp(Q) 执行。W-timeStamp(Q) = max{ TS (Ti), W-timeStamp(Q) }
封锁的粒度
封锁粒度:封锁对象的大小
封锁对象:属性、元组、关系、数据库
多粒度封锁
封锁原则
(1). 需要处理大量元组的事务以关系为封锁粒度
(2). 需要处理多个关系的大量元组的事务以数据库为封锁粒度
(2). 处理少量元组的事务以元组为封锁粒度
多粒度树
四级多粒度树:数据库。关系。元组。列。
多粒度树封锁协议
特点:可对多粒度树中每一个节点独立加锁。
多粒度树封锁方式
显式封锁:直接加在数据对象上的锁。
隐式封锁:上级结点加锁而导致的锁
意向锁
封锁冲突检查:(1) 与显式封锁冲突。(2) 显式与隐式冲突。
问题:检查效率低。解决方法:引进意向锁。
意向锁加锁原则
该结点的下层结点正在被加锁。对任一结点加锁时,对上层结点加意向锁。
封锁冲突检查对象:上层结点,本结点。
意向锁的种类
(1). 意向共享锁(IS锁)
数据A加S锁。向上加IS锁。
(2). 意向排他锁(IX锁)
数据A加X锁。向上加IX锁。
(3). 共享意向排他锁(SIX)
数据A加S锁,向上加SIX锁。
SIX锁的意义:如果一个会话的事务当前持有了某个表或者数据页的S锁,而它接下来又要去修改表中的某一个行。这种情况下,事务需要获取行上的X锁和表或数据页上的IX锁,但是SQL Server只允许一个会话在一个资源上获取一个锁。也就是说没有办法在已经获得表或者页级别的S锁之后又分配IX给它。为了解决这个问题,于是就出现了两者的结合体:S+IX=SIX。 同理,如果先持有IX,再去获取S,也会得到SIX。
补充:事务的隔离级别与三级锁
脏读:T1事务执行,T2事务执行。T1更新数据Data,但失败,回滚。在回滚前,T2读取更新后的数据Data。重点:回滚,操作失败的脏数据
不可重复读:T1读取数据后,T2执行更新操作,T1无法再现前一次读取结果。重点:T2执行成功,数据更新。a) 某事务两次读取数据得到值不同。b) 某事务两次读取数据,记录丢失。c) 某事物两次读取数据,记录增加。
幻读:不可重复读的后两种情况。
更新丢失:T1、T2读入同一数据并修改。T2提交的结果破坏了T1提交的结果。
a) T1事务撤销,覆盖T2事务。 b) T1事务成功,覆盖T2事务。
一级封锁协议:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。 一级封锁协议可以防止丢失修改,并保证事务T是可恢复的。使用一级封锁协议可以解决丢失修改问题。在一级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,它不能保证可重复读和不读“脏”数据。 重点:X锁的作用
二级封锁协议:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后方可释放S锁。 二级封锁协议除防止了丢失修改,还可以进一步防止读“脏”数据。但在二级封锁协议中,由于读完数据后即可释放S锁,所以它不能保证可重复读。 重点:S锁的作用
三级封锁协议:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。 三级封锁协议除防止了丢失修改和不读“脏”数据外,还进一步防止了不可重复读。重点:扩展S锁的范围为事务前后(原来是数据前后)
PS:封锁协议是手段,隔离级别是结果。图显示的结果是,达到该结果能够解决的问题。
参考资料:
《数据库系统概述》
SIX锁