Transaction ProcessingⅠ
Databases protection
数据库保护:排除和防止各种数据的干扰破坏,确保数据安全可靠,以及在数据库遭到破坏后尽快的恢复
数据库保护方式:
1)数据库的恢复技术
2)并发控制技术
3)完整性控制技术
4)安全性控制技术
数据库的一致性
-
一致性状态:满足所有完整性约束
一致性数据库:处于一致性状态的数据库
注意数据库并不是一直处于一致性状态:
-
一致性事务
定义:事务是一个不可分割的操作序列,其中的操作要么都做,要么不做
例子:
性质:ACID(原子性、一致性、独立性、持久性)
状态:
Start T>: Transaction has started
Commit T>: Transaction has finished, and all modifications are all refelected to disks
Abort T>: T has been terminated and all modifactions have been canceled
原语操作:
Input(x)、Output(x)、Read(x,t)、Write(x,t)
银行转账事务例子T1: r1(A)w1(A)r1(B)w1(B)
Read(A,t)
t = t - 100
Write(A,t)
Read(B,t)
t = t + 100
Write(B,t)
Output(A)
Output(B)
SQL对事务的支持
1)SQL标准:Begin Transaction、Commit Transaction、Rollback Transaction
2)Oracle:Commit、Rollback(无Begin Transaction,一旦建立数据库就认为事务开始)
Oracle中的事务设置
Sql>set autocommit=on #设置每次语句执行都自动commit
Sql>set autocommit=false
Sql>update student set age = age - 1
Sql>rollback#取消前面的更新操作
Sql>update student set age = age + 1
Sql>commit
数据库系统故障分析
数据库一致性可能由于故障被破坏
1)事务故障
2)介质故障
3)系统故障
-
事务故障:发生在单个事务内部的故障
1)可预期的事务故障:转账余额不足,应用程序可以解决
2)非预期的事务故障:运算溢出、死锁,应用程序无法解决,由系统解决 -
介质故障:
硬故障:磁盘损坏(破坏整个数据库) -
系统故障
软故障:由于OS、DBMS软件问题或断电导致内存数据丢失,但磁盘数据仍然在(影响现在正在运行的事务,但不破坏整个数据库)
1)未完成事务对数据库的更新已经写入数据库
2)已提交事务对数据库更新还停留在缓冲区没来记得写入数据库 -
数据库系统故障恢复策略
目的:恢复DB到一致状态
基本原则:冗余
实现方法:定期转储整个数据库、建立事务日志、通过备份和日志进行恢复
恢复过程:
Undo日志
- Undo日志文件内容
事务的开始标记 < S t a r t , T > <Start, T> <Start,T>
事务的结束标记 < C o m m i t , T > <Commit, T> <Commit,T>或 < A b o r t , T > <Abort, T> <Abort,T>
事务的更新操作记录<执行操作的事务标识,操作对象,更新前值(插入为空)>
- Undo日志规则
事务的每一个修改操作都生成一个日志记录<T,x,odl-value>
WAL日志:x被写到磁盘之前,对应该修改的日志记录必须已经被写到磁盘上
当所有修改结果都已经写入磁盘后,将<Commit,T>日志记录写到磁盘上
WAL的原因:如果在写完log之后写data之前发生故障,还可以通过日志恢复数据库不一致状态
Undo日志记录
Read(A,t) -------> <Start,T>
t=t-100
Write(A,t) -------> <T,A,1000>
Read(B,t)
t=t+100
Write(B,t) -------> <T,B,2000>
Flush Log
Output(A)
Output(B) (Commit必须在数据写回磁盘之后)
-------> <Commit,T>
Flush Log Log
对于每一处失败,可能出现内存和磁盘中数据不一致的情况
3. 基于Undo日志的恢复
Step1:从头扫描log,将未commit或者abort的事务写入事务列表L中
Step2:从尾部开始扫描<T,X,v>,若
T
∈
L
T\in L
T∈L,则
write(X,v)
Output(X)
Step3:
for each T in L:
write <Abort, T> to log
这里可以看出flush log是更新在磁盘中的日志,因此我们最终选取日志是根据磁盘中的日志来决定是否把T放入L中
最终恢复之后磁盘中的日志应该是
<Start, T>
<T,A,1000>
<T,B,2000>
<Abort, T>
因此我们最后可以看出,Undo日志的主要作用是用来撤销没有及时commit的事务
Redo日志
- Redo日志规则
1)x被写到磁盘之前,对应该修改的Redo日志已经被记录到磁盘上(WAL)
2)在数据被写回磁盘之前,先写<Commit,T>日志记录
3)日志中的数据修改记录:<T,x,v>(其中v是更新后的值)
(注意redo和undo这里的区别,在于<Commit,T>的写入顺序)
Read(A,t) -------> <Start,T>
t=t-100
Write(A,t) -------> <T,A,900>
Read(B,t)
t=t+100
Write(B,t) -------> <T,B,2100>
-------> <Commit,T>
(Commit必须在数据写回磁盘之前)
Flush Log
Output(A)
Output(B)
Flush Log Log
注意在更新磁盘中的日志时,内存中就已经更新了<Commit,T>
- 基于Redo日志的恢复
Step1:从头扫描日志,找到所有有<Commit,T>的事务并放入L中
Step2:从首部开始扫描日志记录<T,x,v>,如果 T ∈ L T\in L T∈L,可能还未写入磁盘
write(X,v)
outpur(X)
Step3:不在L中的事务说明还没有写到磁盘中,不会出现不一致的情况
for each T not in L:
write <Abort, T> to log
- Undo对比Redo
对于Undo来说,每个数据在内存中运算完成之后可以立即写入磁盘中,所有数据写完之后再commit,减少占据内存的时间;但是对于Redo来说,对于每个数据需要在内存中一直维持直到最后一起写入磁盘中,并在写之前进行commit。
恢复的时候,对于Undo,每一个还未commit的数据均有可能在磁盘中不一致;对于Redo,因为数据都是最后一起写回磁盘,所以尚未commit的数据一定不会在磁盘中引起冲突,所以只需要处理commit的数据
Undo/Redo日志
1)在x被写入磁盘之前,对应该修改的日志记录必须已被写到磁盘上(WAL)
2)日志中的数据修改记录<T,x,v,w>v对应旧值,w对应新值
- 基于Undo/Redo日志的恢复
Step1:将commit的事务记录进undo列表中,反之记录进redo列表中
Step2:反向扫描日志,对于Undo表中的<T,X,v,w>执行
write(X,v);Output(X)
Step3:正向扫描日志,对于Redo表中的<T,X,v,w>执行
write(X,w);Outpur(X)
Step4:对于undo表中的T写入<Abort,T>
注意到需要先Undo后Redo
检查点
因为若系统发生故障,需要对整个日志进行扫描,搜索耗时很长
-
简单检查点
周期性地
1)不接受任何新事务
2)等待知道所有事务都停止或者提交
3)刷新所有的日志到磁盘中
4)刷新所有的缓存到磁盘中
5)把检查点记录写到磁盘上
6)恢复事务 -
基于检查点的恢复
只需要再检查点之后的日志文件进行扫描恢复即可,检查点前已经commit的事务不需要redo
日志轮转技术
数据库日志产生很快,大量早点的日志都随着时间推移都已经失效了,因此可以用轮转技术维持一定数量的日志即可