开篇
- 这篇博客,大部分知识点来自于 课本 《数据库系统概论》 及 B站搜索的视频讲解,做下总结记录。
MySQL版本 5.6
- 基础架构
一:事务的特性(ACID)与恢复机制:
什么是事务:
- 事务是 用户所定义的一个数据库操作序列, 这些操作要么全做,要么全不做,是一个不可分割的工作单位。一个事务可以是一条sql语句,一组sql语句或整个程序。
(1)原子性
- 事务时数据库中的逻辑工作单位,事务中包括的诸操作要么全做,要么都不做。保持原子的特性。
(2)一致性
- 事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。 一致性和 原子性密切相关,就如银行取钱,A账户取出一万元放到B账户,两个操作,A减少,B增加。 要么全做,要么全不做,都是处于一致性状态。
(3)隔离性
- 事务之间是独立的,一个事务的执行不能被其他事物所干扰。既一个事务的内部操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能相互干扰。
(4)永久性(持续性)
- 顾名思义,指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其执行结果有任何影响。
ACID是事务管理的重要任务,遭破坏的情况
- (1)多个事务并行执行时,不同事务的操作交叉执行
- (2)事务在运行过程中被强制停止。
解析
:第一种情况,数据库管理系统必须保证多个事务的交叉运行,不影响事务的原子性。第二种情况下,数据库管理系统必须保证被强行终止的事务对数据库和其他事务没有任何影响。 这些就是数据库管理系统中恢复机制和并发控制机制的责任!!!
。
数据库恢复
- 保证数据库的安全性和完整性不被破坏,保证并发事务的正确执行 。
恢复子系统
: 是数据库系统的一个重要组成部分,相当庞大,占整个系统代码的10%以上!因为一些故障(种类很多),比方说难以预料,预防的 计算机系统硬件的故障,软件的错误,操作人员失误等,导致事务非正常中中断,影响数据库中数据的正确性,甚至破坏数据库,就需要这个数据库恢复功能,将数据库从错误状态恢复到某一已知的正确状态(就是一致性状态或者叫完整状态)。-
故障的种类:
- (1)事务内部故障: 分为两种 可预期的,不可预期的。
- 可预期的: 比如说A 向B转账的例子, 若A账户没有足够的金额,可能导致操作失败,是可预期的故障错误。程序可自动判断,然后程序内执行回滚等操作。
- 不可预见的:占比较多,主要是不可预期的,不能由应用程序进行处理,如运算溢出,并发事务发生死锁,违反完整性限制等被终止。
- 事务的故障意味着事务没有达到预期的的重点**(COMMIT或者显示的ROOLLBACK)** ,处于不正确的状态。
事务撤销(UNDO):
就是恢复程序要在不影响其他事务运行的情况下,强行回滚该事务,及撤销该事务已经做出的任何对数据库的修改。
- (2)系统故障: 指造成系统停止运转的任何事件, 使得系统要重新启动。比如说(CPU故障),系统断电,操作系统故障,DBMS代码错误等。
- 这类故障是影响正在运行的所有事务的 ,但是不会破坏数据库。同样导致事务非正常终止,此时主存内容,尤其是数据库缓冲区(在主存)中的内容都丢失。一些尚未完成的事务的结果可能已经送入到磁盘中物理数据库里,影响数据的一致性。需要 恢复子系统在系统重启的时候,让所有的不正常事务都回滚,强行撤销所有未完成的事务。
- 需要注意: 系统故障可能导致 已完成的事务可能有一部分甚至全部留在缓冲区,尚未写入到物理磁盘中的数据库中 ,这时候就不是需要撤销全部操作了,而是事务正常执行完提交操作,需要将这些已经提交的结果,重新写入数据库,称为:
重做(REDO)
。 - 总结:重启系统一般有两个操作:UNDO 和 REDO。
- (3)介质故障,又称为硬故障。系统故障称为软故障。
- (4)计算机病毒 这些就不去介绍了。
- 恢复的基本原理:
冗余
。数据库中任何一部分被破坏或数据不正确,可以根据存储在系统别处的冗余数据来重建。
- (1)事务内部故障: 分为两种 可预期的,不可预期的。
-
恢复的实现技术
恢复机制
涉及到两个关键问题:如何建立冗余数据 和 如何运用冗余数据实施数据库的恢复。- (1)建立冗余
- 建立冗余数据最常用的技术是数据转储 和 登记日志文件(logging)。通常在一个数据库系统中,两种方法是一起使用的。
- 1. 数据转储: 就是 数据库管理员定期将整个数据库复制到磁盘等存储介质上保存起来,这些后别的数据称为 后备副本。
- 当数据库遭到破坏时,可以(1)重装后备副本,接着(2)继续运行所有更新事务,是数据库恢复到故障发生前的一致性状态。
- 转储非常耗时,不能经常进行,应该定期,设置一个转储周期。
- 静态转储:系统无事务运行的情况下,进行转储操作。
- 动态转储:指进行转储期间,也允许对数据进行存取和修改。转储和事务可以并发执行,此时因为转储的过程中,还有事务进行运行, 那么打个比方: 当前转储 A字段值为 100,写入磁盘,但是当前事务有运行,将A修改为150,导致 转储的 A字段是过期数据。 要解决这个问题,就需要转储期间,对所运行的所有 事务对数据库的修改活动记录下来,建立日志文件(log file) 。 后备副本,加上日志文件,就能将数据库恢复到某一时刻的正确状态! 神奇,巧妙~
- 根据场合还能分为 海量转储 和 增量转储。海量转储就是一次性转储全部数据库,增量转储,只是转储上一次转储到现在的 更新过的数据。
一共分为如下四种了:
- (2)登记日志文件
- (1)日志文件的格式和内容:
- 日志文件是用来记录事务对数据库的更新操作的文件。基本分为两种格式,以记录为单位的日志文件, 以数据块为单位的日志文件。
以记录为单位的日志文件
:需要登录的内容包括:- 各个事务的开始(BEGIN TRANSACTION )标记
- 各个事务的结束(COMMIT 或 ROLLBACK)标记
- 各个事务的所有更新操作
- 每一个事务的开始标记,结束标记,更新操作,均为日志文件的一个
日志记录(log record)
- 每个日志记录的主要内容包括
- 事务标识(标明是哪个事务)
- 操作类型(增删改)
- 操作对象(记录内部标识)
- 更新前记录的旧值(增加操作,这里为空)
- 更新后数据的新值(删除操作,这里为空)
- 每个日志记录的主要内容包括
以数据块为单位的日志文件:
- 包括:事务标识和被更新的数据块
- 将更新前和更新后的整个块都放入到日志文件中。
- (2)日志文件的作用
- 日志文件可以进行事务故障恢复和系统故障恢复,并协助后备副本进行介质故障恢复
- 1 事务故障恢复和系统故障恢复必须使用日志文件
- 2 在动态转储中,必须建立日志文件。
- 3 静态转储中,可以建立日志文件,当数据库毁坏后可重新装入后备副本,利用日志对已完成事务进行重做处理。
- (3)登记日志文件:保证数据库是可恢复的,必须遵守两条原则
- 登记的次序严格按照并发事务执行的时间次序
- 必须先写日志文件,后写数据库。
- (1)日志文件的格式和内容:
- (3)恢复策略
- 事务故障恢复:事务在运行中非正常终止, 恢复子系统用 日志文件撤销(UNDO)此事务对数据库的修改。此过程对用户透明,系统自动完成。步骤如下
- 1 反向扫描日志文件(从后往前找,最近的操作记录)查找该事务的更新操作。
- 2 对该事务的更新操作执行逆操作,将日志记录“更新前的值”写入数据库。
- 3 一直到读取到事务的开始标记,事务的恢复就算完成了
- 系统故障的恢复:主要步骤就是 撤销故障发生时未完成的事务,重做已完成的事务。具体步骤:
- 1 正向扫描日志文件(从头到尾)找出故障发生前已经提交的事务(有BEGIN TRANSACTION COMMIT 操作的事务) 将其标记到重做队列中(REDO-LIST)。同时找到尚未完成的事务,将事务标识记录到撤销队列中(UNDO-LIST)。
- 2 对撤销队列中的各个事务进行撤销处理。反向扫描日志文件,进行撤销。
- 3 对重队列的事务进行处理,正向扫描日志文件,对每个事务重新进行 日志文件的登记操作, 将更新后的值,写入到数据库。
- 事务故障恢复:事务在运行中非正常终止, 恢复子系统用 日志文件撤销(UNDO)此事务对数据库的修改。此过程对用户透明,系统自动完成。步骤如下
- (4)具有检查点的恢复技术
- (5)数据库镜像 这些就不具体介绍了,我也不是很了解,一时间不容易读的很通透。
二: 事务隔离级别与缺陷:
- 读取未提交(Read Uncommitted):
- 读取以提交(Read Committed):
- 可重复读(Repeatable Read):
- 串行化(Serializable):
- 事务的并发操作导致数据的不一致性包括下面几点:
- 丢失修改
- 脏读:
- 幻读:
- 不可重复读:
三:什么是并发控制?
(1)什么是并发控制?
- 事务是并发控制的基本单位,为了保证事务的
隔离性
和一致性
,数据库管理系统需要对并发操作进行正确调度。这就是数据库中的 并发控制机制。
(2)并发操作带来的数据不一致性:
- 1
丢失修改(lost update):
两个事务 T1 ,T2同时读入同一数据并修改,T2的提交结果破坏了T1提交的结果,导致T1的修改被丢失。举个例子。 T1 读到 A = 16 执行 A - 1 操作此时 A = 15. 但是 B读到A = 16, 执行 A - 1操作,导致 A 最后的值 还是 15, 丢失了T1的修改操作,最终结果本该是 14。 - 2
脏读(dirty read)
: T1事务读入一个数据,并且修改了其结果写入磁盘数据库,T2事务此时读取了T1修改后保存到磁盘的数据,但T1因为某些原因,被撤销回滚,此时T2读到的就是脏的数据,这就是脏读,即读到不正确的数据。 - 3
不可重复读(non-repeatable read)
:事务T1读取数据后,事务T2执行更新操作,使T1无法再次读取前一次读取的结果。具体的讲不可重复读包括以下三种情况:- (1) 事务T1读取某一次的数据后, 事务T2对其进行了修改,当事务T1再次读取该数据时得到与前一次不同的值。
- (2) 事务T1按一定的条件从数据库中读取了某些数据记录后,事务T2 删除了其中的部分记录,当T1再次按相同条件读取数据时,发现数据神秘消失了。
- (3)事务T1 按照一定条件从数据库中读取某些数据后,T2又插入了一些记录,当T1再次按照不同的条件进行读取数据时,发现多了一些数据。(幻读)
幻读
: 2,3的情况,删除和增加操作,导致读取不一致,通常也被称为幻读,读取到的数据量不同。不可重复读
: 感觉多指情况1, 对已有的数据进行修改操作。
(3) 并发控制机制
-
并发控制的技术主要有 封锁(locking),时间戳(timestamp), 乐观控制法,多版本并发控制(MVCC)。
-
1. 封锁:
- 封锁是实现并发控制的一个非常重要的技术。事务对某个数据对象操作之前进行加锁,保证数据的安全性。 有两种:1. 排他锁(简称为X锁,写锁)。 2. 共享锁(简称为S锁,读锁)。 二者常称为:
读写锁
。 - 排他锁: 又称为写锁。事务T对数据对象A加上X锁,则只允许T读取和修改A。期间其他事务不能对A加任何类型的锁,也不能读取和修改A。
- 共享锁:又称为读锁。 若事务T对数据对象A加上S锁,事务A可以读A,但是不能修改A。 期间其他事务只能只能对A加上 S锁。保证了其他事务可以读A,但是在T释放A上的S锁之前不能对A做任何修改操作。
- 封锁协议: 在运用X锁和S锁对数据对象进行加锁时,还要约定一些规则,不是随便加的。封锁协议就决定了合适申请X,S锁,封锁时间,何时释放等。下面一共介绍
三级
封锁协议。在不同程度上解决了丢失修改,脏读, 幻读,不可重复读
等问题。-
一级封锁协议
- 介绍:
事务T在修改数据R之前,必须先对其加上 X锁,直到事务结束才释放。
事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。 - 作用: 可以防止丢失修改,保证事务T是可恢复的。如图a
- 图a,在对事务T1 进行修改之前先对 A加X锁。保证其他事务不能操作。
- 解决:仅仅对数据进行读是不需要加锁的,它不能保证可重复读还有 脏读。
- 介绍:
-
二级封锁协议
- 介绍:
在一级封锁协议的基础上,增加事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁
。 - 作用:除了防止丢失修改,还进一步防止脏读。
- 图c,事务T1 对C进行修改之前,先对C加上X锁,修改其值后,写回磁盘。这时T2 请求在 C 上加上S锁,需要等待 T1 释放X锁,只能等待。 T1因为某种原因被撤销,C恢复100,T1释放C上的X锁后,T2获得C上的S锁,读 C = 100. 避免了脏读。
- 问题:因为读取完数据后即可释放S锁,所以它不能保证可重复读
- 介绍:
-
三级封锁协议
- 介绍:
在一级封锁协议的基础上增加了事务T在读取数据R之前必须先对其加S锁,(与二级的区别)直到事务结束才释放。
- 作用: 防止了 丢失修改, 脏读, 不可重复读。
- 图b, 事务T1 在读A,B之前,先对A,B 加S锁,这样其他事务只能对它们加 S锁,不能加X锁,保证其他事务只读不能修改它们。 直到T1 读取完后,计算结果,T1事务结束,T2才能获得B的X锁。
- 介绍:
- 图片:
- 总结:三种协议的主要区别在于
什么操作!
需要申请封锁,以及何时释放锁
(持锁时间)不同封锁协议是事务达到的一致性级别是不同的,封锁级别越高,一致性程度越高。如图总结:
-
- 封锁是实现并发控制的一个非常重要的技术。事务对某个数据对象操作之前进行加锁,保证数据的安全性。 有两种:1. 排他锁(简称为X锁,写锁)。 2. 共享锁(简称为S锁,读锁)。 二者常称为:
-
全称: Multi-Version Concurrency Control,多版本并发控制。
-
主要作用是提高数据库的并发性能。主要用来处理
读请求(指的是快照度,而不是当前读)
。 -
当前读:
悲观锁,就是需要使用锁来保证的,如,insert(排他锁), delete(排他锁),update(排他锁)操作, select lock in share mode(共享锁),select for update(排他锁),这些加锁的操作就是当前读。 -
快照读
:普通的快照读。实现是基于多版本并发控制。就是MVCC,多版本,也就是说读到的数据不一定是当前最新的数据,有可能是历史版本的数据。