数据库系统原理

数据库系统原理的总结

事务

什么是事务

事务指满足ACID特性的一组操作

ACID是什么

原子性、一致性、隔离性、持久性

什么是原子性

要么操作全部成功,要么全部失败

原子性实现原理

innoDB实现回滚,靠的是undo log,通过undo log做与之前相反的操作实现回滚,保证原子性

什么是一致性

所有事务对同一数据的读取结果相同

一致性实现原理

原子性、隔离性、持久性以及应用层的保障

什么是隔离性

一个事务完成前,对其他事务不可见

隔离性实现原理

锁机制和MVCC

什么是持久性

一旦事务提交(完成),则所作修改永远保存

持久性实现原理

innoDB通过缓存(Buffer Pool,定期刷盘)提高读写数据效率,但MySQL宕机时会导致数据丢失,于是引入redo log,当数据修改时,先在redo log中记录本次操作所有修改,之后修改Buffer Pool数据;事务提交时,会调用fsync接口对redo log进行刷盘,如果宕机,重启时可以读取redo log中的数据,对数据库进行恢复

redo log与bin log的区别

作用不同:redo log保证宕机也不会影响持久性,bin log保证服务器可以基于时间点恢复数据和主从复制

层次不同:redo log时innoDB存储引擎实现的,bin log时服务器层实现的

内容不同:redo log是物理日志,内容基于磁盘Page;bin log内容是二进制的

写入时机不同:bin log在事务提交时写入; redo log写入时间相对多元

锁机制

按照粒度,分为表锁和行锁

读写锁

X:写锁(互斥锁)、S:读锁(共享锁)

意向锁

一个事务在获得某个数据行对象的 S 锁之前,必须先获得表的 IS 锁或者更强的锁;

一个事务在获得某个数据行对象的 X 锁之前,必须先获得表的 IX 锁。

封锁协议

三级封锁协议
  • 一级封锁协议:事务 T 要修改数据 A 时必须加 X 锁,直到 T 结束才释放锁
  • 二级封锁协议:在一级的基础上,要求读取数据 A 时必须加 S 锁,读取完马上释放 S 锁
  • 三级封锁协议:在二级的基础上,要求读取数据 A 时必须加 S 锁,直到事务结束了才能释放 S 锁
两段锁协议

加索和解锁分两个阶段进行

隐式与显示锁定

MySQL 的 InnoDB 存储引擎采用两段锁协议,会根据隔离级别在需要的时候自动加锁,并且所有的锁都是在同一时刻被释放,这被称为隐式锁定。

InnoDB 也可以使用特定的语句进行显示锁定:

1
select ... lock in share mode;
2
select ... for update;

并发一致性问题

丢失修改、脏读、不可重复读、幻影读

什么是丢失修改

A和B对同一数据修改,A改完后B改,A修改被覆盖

什么是脏读

A修改数据,B读取该数据,随后A撤销本次修改

什么是不可重复读

A读数据,B对该数据进行修改,A再读取该数据

什么是幻影读

A读某个范围数据,B在该范围内插入新数据,A再读该范围数据

事务隔离级别

未提交读、提交读、可重复读、可串行化

未提交读

未提交的事务对其他事务也有可见性

提交读

一个事务提交前对其他事务不可见

可重复读

保证在同一事务多次读取同一数据结果一致

可串行化

强制事务串行执行

MVCC

同一时刻不同事务读取的版本可能不同

解决脏读

img

解决不可重复读

img

解决幻影读

img

范式理论

函数依赖

A->B:B依赖A,A决定B

如果 {A1,A2,… ,An} 是关系的一个或多个属性的集合,该集合函数决定了关系的其它所有属性并且是最小的,那么该集合就称为键码

对于 A->B,如果能找到 A 的真子集 A’,使得 A’-> B,那么 A->B 就是部分函数依赖,否则就是完全函数依赖

对于 A->B,B->C,则 A->C 是一个传递函数依赖

异常

以下的学生课程关系的函数依赖为 {Sno, Cname} -> {Sname, Sdept, Mname, Grade},键码为 {Sno, Cname}。也就是说,确定学生和课程之后,就能确定其它信息。

Sno Sname Sdept Mname Cname Grade
1 学生-1 学院-1 院长-1 课程-1 90
2 学生-2 学院-2 院长-2 课程-2 80
2 学生-2 学院-2 院长-2 课程-1 100
3 学生-3 学院-2 院长-2 课程-2 95

不符合范式的关系,会产生很多异常,主要有以下四种异常:

  • 冗余数据:例如 学生-2 出现了两次。
  • 修改异常:修改了一个记录中的信息,但是另一个记录中相同的信息却没有被修改。
  • 删除异常:删除一个信息,那么也会丢失其它信息。例如删除了 课程-1 需要删除第一行和第三行,那么 学生-1 的信息就会丢失。
  • 插入异常:例如想要插入一个学生的信息,如果这个学生还没选课,那么就无法插入。

范式

第一范式

属性不可分

第二范式

每个非主属性完全函数依赖于键码。

可以通过分解来满足。

分解前

Sno Sname Sdept Mname Cname Grade
1 学生-1 学院-1 院长-1 课程-1 90
2 学生-2 学院-2 院长-2 课程-2 80
2 学生-2 学院-2 院长-2 课程-1 100
3 学生-3 学院-2 院长-2 课程-2 95

以上学生课程关系中,{Sno, Cname} 为键码,有如下函数依赖:

  • Sno -> Sname, Sdept
  • Sdept -> Mname
  • Sno, Cname-> Grade

Grade 完全函数依赖于键码,它没有任何冗余数据,每个学生的每门课都有特定的成绩。

Sname, Sdept 和 Mname 都部分依赖于键码,当一个学生选修了多门课时,这些数据就会出现多次,造成大量冗余数据。

分解后

关系-1

Sno Sname Sdept Mname
1 学生-1 学院-1 院长-1
2 学生-2 学院-2 院长-2
3 学生-3 学院-2 院长-2

有以下函数依赖:

  • Sno -> Sname, Sdept
  • Sdept -> Mname

关系-2

Sno Cname Grade
1 课程-1 90
2 课程-2 80
2 课程-1 100
3 课程-2 95

有以下函数依赖:

  • Sno, Cname -> Grade

第三范式

非主属性不传递函数依赖于键码。

上面的 关系-1 中存在以下传递函数依赖:

  • Sno -> Sdept -> Mname

可以进行以下分解:

关系-11

Sno Sname Sdept
1 学生-1 学院-1
2 学生-2 学院-2
3 学生-3 学院-2

关系-12

Sdept Mname
学院-1 院长-1
学院-2 院长-2

参考资料:

深入学习MySQL事务:ACID特性的实现原理

CS-Notes

  • © 2020 QSH
  • Powered by Hexo Theme Ayer
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信