系统篇
数据库恢复技术
事务
定义:指用户定义的一个数据库操作序列(简单说就是指要做的或所做的事情),这些操作要么全做,要么全不做,是一个不可分割的工作单位
一个程序中包含多个事物
事物是恢复和并发控制的基本单位
- 事务原则(ACID原则)
- 原子性(Atomicity):要么都成功,要么都失败;
- 一致性( Consistency):事务前后数据完整性要保持一致;
- 隔离性或独立性(Isolation):事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,事务之间要相互隔离;
- 持续性(Durabilily):事务提交,事务一旦提交则不可逆,被持久化到数据库中;
> mysql是默认开启事务自动提交的
手动处理事务前需要先关闭自动提交
set autocommit = 0;
事务开启
start transaction--标记一个事务的开始,从这之后的sql都在同一个事物内
insert xx;
insert yy;
提交:持久化(成功)
commit
回滚:回到原来的样子,就是数据提交前(失败)
rollback
事务结束
set autocommit = 1 --开启自动提交
设置一个事务的保存点
savepoint 保存点名;
回滚到保存点
rollback to savepoint;
撤销保存点
release savepoint 保存点;
模拟转账
创建数据库shop
create database shop;
切换数据库
use shop;
创建account表
create table `account`(
`id` int(5) not null auto_increment,
`name` varchar(20) not null,
`money` decimal(9,2) not null,
primary key(`id`)
)engine=innodb default charset=utf8;
插入数据
insert into `account`(`name`,`money`)
values(`A`,20000.00),(`B`,100.00);
---------------模拟转账-----------------
关闭自动提交事务
set autocommit = 0;
开启一个事务
start transaction;
A减50
update account set money=money-50 where `name` = 'A';
B加50
update account set money=money+50 where `name` = 'B';
提交事务,就被持久化了
commit;
/回滚
rollback;
回复默认值
set autocommit = 1;
故障的种类
- 事物内部故障:非预期的故障居多
- 事物故障的恢复:事物撤销(UNDO):强行回滚该事物,撤销该事物已经作出的任何对数据库的修改,使该事务像根本没有启动一样
- 系统故障(软故障):故障发生更严重,特定类型的硬件错误(如CPU故障),操作系统故障,数据库管理系统代码故障,系统断电
- 一些还未完成的事物结果可能已经送入数据库,造成数据库不正确,恢复策略:系统重启时,回滚所有非正常事务,强行撤销所有未完成的事务
- 一些事务尚未写回到磁盘上的数据库中,系统故障使得这些事务对数据库的修改部分或全部丢失,恢复策略:系统重新启动时,恢复程序需要重做(REDO)所有已提交的事务;
- 介质故障
- 计算机病毒
数据库恢复
一个数据库管理系统必须具有把数据库从错误状态恢复到某一已知的正确状态(或称一致状态或完整状态)的功能
- 恢复子系统是数据库管理系统的一个重要组成部分
- 恢复技术是衡量系统优劣的重要指标
恢复实现的技术
恢复的基本原理:冗余
引出:
如何建立冗余数据?
如何利用冗余数据实现数据库恢复?
两种恢复技术:
- 数据转储
- 登记日志文件
一般都是两种技术配合共同使用
数据转储
什么是数据转储?
数据库管理员DBA定期将整个数据库复制到磁盘,磁带或其他存储介质上保存起来的过程,这些备用的数据叫后备副本(其实就是我们经常说的备份)
主要的转储方式:
按转储状态分为:
- 静态转储:在系统无事务运行状态下进行的转储操作,这样做保证转储得到的一定是一个一致性的副本
- 动态转储:转储期间允许转储和用户事务并发进行,但是不能保证最后得到的副本数据的准确性,所以使用动态转储应该配合日志文件一起使用
按转储方式分为:
- 海量转储:每次转储全部数据库
- 增量转储:每次只转储上一次转储后更新过的数据
因此数据转储可以分为四类:
- 静态海量转储
- 静态增量转储
- 动态海量转储
- 动态增量转储
登记日志文件
什么是日志?
用来记录事务对数据库的更新操作的文件,日志记录了对数据库的每一步操作,日志是数据库恢复的重要手段
日志文件格式:
- 以记录为单位的日志文件
- 日志文件需要登记的内容:
- 各个事务的开始
- 各个事务的结束
- 各个事务的所有更新操作
- 每个日志记录的内容:
- 事务的标识
- 操作的类型
- 操作对象
- 更新前数据的旧值
- 更新后数据的新值
- 日志文件需要登记的内容:
- 以数据块为单位的日志文件
- 每个日志记录内容:
- 事务标识
- 被更新的数据块
- 每个日志记录内容:
日志文件的作用?
- 事物内部故障和系统故障必须使用用日志文件
- 动态转储方式中必须建立日志文件,后备副本和日志文件相结合才能有效地恢复数据库
- 静态转储也可以建立日志文件,当数据库毁坏可重新装入后备副本把数据库恢复到转储结束时刻正确地状态
登录日志文件需要遵守地两条原则:
- 登记地次序严格按照并发事务执行地时间次序
- 必须先写日志文件,后写数据库
恢复策略
事务故障策略
事务在运行至正常终点前被终止
恢复策略:由恢复子系统利用日志文件撤销此事务已对数据库进行的修改
另外,事务内部故障的恢复是由系统自动完成的,对用户是透明的,不需要用户干预
具体步骤;
- 反向扫描日志文件,查找事务的更新操作
- 对该事务执行的更新操作执行逆操作,即将日志记录中“更新前的值”写入数据库
- 继续反向扫描日志文件,查找该事务的 其他更新操作,并作同样处理
- 如此下去,直至读到此事务的开始标志,事务故障恢复完成
这里还有系统故障策略,介质故障策略就不介绍了
并发控制
并发操作破坏了事务的隔离性,并发操作带来的数据不一致性包括:
- 丢失修改(读-读操作)
- 不可重复读(读-写操作)
- 读“脏”数据(写-读操作)
并发控制的主要技术:封锁(Locking),时间戳,乐观控制法和多版本并发控制等
封锁
就是事务T在对某个数据对象操作之前,先向系统发出请求,对其加锁,加锁后的事务T对该数据对象的操作有了一定的控制,在事务T释放锁之前,其他事务就不能更新此数据对象
基本的封锁类型:
- 排他锁(X锁/写锁):事务T对数据对象A加上X锁,其他事务在事务T释放数据对象A之前不能再读取和修改A
- 共享锁(S锁/读锁):事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加M锁,直到T释放A上的S锁为之,这样做保证其他事务可以读取数据对象A,但是不能修改A
封锁协议
运用X锁和S锁给数据对象加锁时,需要约定一些规则,这些规则为封锁协议
- 何时申请X锁或S锁
- 释放事件
- 何时释放
三级封锁协议
- 一级封锁协议
- 事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放,所以可防止丢失修改
- 二级封锁协议
- 在一级封锁协议的基础上增加事务T在读取数据R之前必须先加S锁,读完后即可释放,所以可防止丢失数据和读“脏”数据
- 三级封锁协议
- 在一级封锁协议的基础上增加事务T在读取数据R之前必须先加S锁,事务结束时才释放,所以可防止丢失数据,不可重复读和“读”脏数据
三级协议的主要区别:
什么操作需要申请封锁以及何时释放锁
活锁和死锁
活锁
事务T封锁R,事务T2又请求封锁R,于是T2等待,T3也请求封锁R,于是T3也等待。。。。
出现多个事务请求同一个数据对象申请加锁的情况:
采用先来先服务的策略
死锁
出现事务T1封锁R1,事务T2封锁R2,然后事务T1又请求R2,事务T2又请求R1,T1,T2互相等待,形成死锁
解决方法:
- 预防死锁发生(不适用)
- 一次封锁法:将要用到的数据对象都加锁,很困难,很难精确确定封锁对象,降低并发度
- 顺序封锁法:预先对数据对象规定一个封锁顺序,所有事物都按这个顺序实行封锁
- 允许死锁发生
- 诊断
- 超时法:设置一个事务的等待时间,超过规定时间时限,就认为发生了死锁
- 等待图法:用事务等待图动态反映所有事务的等待情况,如果发现图中存在回路,则表示系统中出现了死锁
- 解除
- 选择一个处理死锁代价最小的事务,将其撤销
- 释放此事务持有的所有的锁,使其它事务能继续运行下去
- 诊断