数据库系统原理
2021-04-16 16:18:09 12 举报
AI智能生成
学习笔记
作者其他创作
大纲/内容
事务
概念
事务是指满足ACID特性的一组操作,可以通过commit提交事务,也可以通过rollback回滚
ACID
Atomicity(原子性):事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。回滚可以用回滚日志(Undo log)实现
Consistency(一致性):一个或多个事务执行后,原来一致的数据和数据库任然一致,主要涉及事务的原子性
Isolation(隔离性):一个事务在提交前的所有修改对其他事务不可见
Durability(持久性):一旦事务提交后,所做的修改将永远保存在数据库中,即使数据库发生崩溃,事务执行的结果也不能丢失。
系统发生崩溃可用重做日志(redo log)来恢复,从而保证数据持久性。与回滚日志记录的是逻辑数据的修改
不同,重做日志记录的是数据页的物理修改
系统发生崩溃可用重做日志(redo log)来恢复,从而保证数据持久性。与回滚日志记录的是逻辑数据的修改
不同,重做日志记录的是数据页的物理修改
并发一致性问题
产生原因
产生并发不一致性问题的主要原因是破坏了事务的隔离性,解决方法是通过并发控制来保证隔离性。并发控制可以通过封锁来实现,但是封锁操作需要用户自己控制,相当复杂。数据库管理系统提供了事务的隔离级别,让用户以一种更轻松的方式处理并发一致性问题
丢失修改
一个事务的修改被另一个事务的修改所替换。例如:两个事务同时对一个数据修改,T1先修改并提交生效,T2随后修改,T2的修改覆盖了T1的修改
读脏数据
读脏数据是指当前事务读到了另一个事务还未提交的数据。例如:一个事务T1对数据进行修改,还未提交。另一个事务T2读到了修改后的数据,此时T1出现问题发生回滚,T2读到的就是脏数据
不可重复读
不可重复读是指在一个事务内多次读取同一数据集合,在这一事务还未结束前,另一个事务也访问了这个数据集合并做了修改,由于第二个事务的修改,第一个事务的两次读取结果可能不一致。例如:T1读取了数据,T2对该数据修改了,如果T1再读了此数据,此时读取结果和第一次读取结果可能不同
幻影读
幻读本质上也属于不可重复读的情况。例如:T1读取了一个范围内的数据,T2在这个范围内插入了一条数据,如果T1再次读取这一范围内的数据,则与第一次读取的结果不一致
封锁
封锁粒度
MySQL 中提供了两种封锁粒度:行级锁以及表级锁
选择封锁粒度策略
封锁类型
读写锁
互斥锁(Exclusive),简称X锁,又称写锁
共享锁(Shard),简称S锁,又称读锁
意向锁
意向互斥锁,简称IX锁
意向共享锁, 简称IS锁
意向锁在原来的 X/S 锁之上引入了 IX/IS,IX/IS 都是表锁,用来表示一个事务想要在表中的某个数据行上加 X 锁或 S 锁
各种锁的兼容关系
封锁协议
三级封锁协议
一级封锁协议
事务 T 要修改数据 A 时必须加 X 锁,直到 T 结束才释放锁
可以解决丢失修改问题,因为不能同时有两个事务对同一个数据进行修改,那么事务的修改就不会被覆盖。
二级封锁协议
在一级的基础上,要求读取数据 A 时必须加 S 锁,读取完马上释放 S 锁。
可以解决读脏数据问题,因为如果一个事务在对数据 A 进行修改,根据 1 级封锁协议,会加 X 锁,那么就不能再加 S 锁了,也就是不会读入数据
三级封锁协议
在二级的基础上,要求读取数据 A 时必须加 S 锁,直到事务结束了才能释放 S 锁。与二级封锁协议区别时,直到事务结束才释放S锁
可以解决不可重复读的问题,因为读 A 时,其它事务不能对 A 加 X 锁,从而避免了在读的期间数据发生改变
两段锁协议
加锁和解锁分为两个阶段进行
可串行化调度是指,通过并发控制,使得并发执行的事务结果与串行化执行的事务结果一致,串行化执行的事务和并发执行的事务互不干扰,不会出现并发一致性问题
事务遵循两段锁协议是保证可串行化调度的充分不必要条件
MySQL 隐式与显示锁定
隐式锁定
MySQL 的 InnoDB 存储引擎采用两段锁协议,会根据隔离级别在需要的时候自动加锁,并且所有的锁都是在同一时刻被释放,这被称为隐式锁定。
显示加锁
SELECT ... LOCK In SHARE MODE;
SELECT ... FOR UPDATE;
SELECT ... FOR UPDATE;
隔离级别
未提交读
事务中的修改,即使未提交,对其他事务也是可见的
提交读
一个事务只能读取已经提交的事务所做的修改
可重复读
保证在同一事务中,多次读取同一数据的结果是一致的
串行化读
强制事务串行执行,这样多个事务互不干扰,不会出现并发一致性问题
多版本并发控制
基本思想
在 MVCC 中事务的修改操作(DELETE、INSERT、UPDATE)会为数据行新增一个版本快照
脏读和不可重复读最根本的原因是事务读取到其它事务未提交的修改。在事务进行读取操作时,为了解决脏读和不可重复读问题,MVCC 规定只能读取已经提交的快照。当然一个事务可以读取自身未提交的快照,这不算是脏读
版本号
系统版本号SYS_ID
是一个递增的数字,每开始一个新的事务,系统版本号就自动递增
事务版本号TRX_ID
事务开启时的系统版本号
Undo 日志
MVCC 的多版本指的是多个版本的快照,快照存储在 Undo 日志中,该日志通过回滚指针 ROLL_PTR 把一个数据行的所有快照连接起来
例子
ReadView
MVCC维护了一个read view结构,主要存储未提交的事务列表{TRX_ID_1,TRX_ID_2,...}以及列表中事务id的最小值TRX_ID_MIN和最大值TRX_ID_MAX
在进行select时,根据当前事务id与TRX_ID_MIN和TRX_ID_MAX之间的关系来判断数据快照是否可用
TRX_ID<TRX_ID_MIN,表示该数据行快照是在当前所有未提交事务之前进行更改的,因此可以使用
TRX_ID>TRX_ID_MAX,表示该数据行快照是在事务启动之后被更改的,因此不可以使用
RX_ID_MIN <= TRX_ID <= TRX_ID_MAX,需要根据隔离级别再进行判断
提交读
如果TRX_ID不在未提交事务列表中,表示该数据行快照已提交,可以使用,否则不能使用
可重复读
都不可以使用。因为如果可以使用的话,那么其它事务也可以读到这个数据行快照并进行修改,那么当前事务再去读这个数据行得到的值就会发生改变,也就是出现了不可重复读问题
当数据行快照不可使用时,需要沿着Undo Log的回滚指针ROLL_PTR找寻下一个快照,再进行上面的判断
快照读与当前读
快照读
MVCC 的SELECT操作读的是快照数据,不需要加锁
当前读
MVCC其他会对数据库进行的修改操作(INSERT,UPDATE,DELETE)需要加锁操作,从而读取最新的数据。可以看到MVCC并不是不用加锁,只是避免了SELECT操作加锁
SELECT 操作也可以强制加锁
Next-Key Locks
作用
MVCC不能解决幻读,在可重复读(REPEATABLE READ)隔离级别下,MVCC+Next-Key Loks可以解决幻影读的问题
子主题
0 条评论
下一页