笔记——MySQL数据库系统原理

事务与ACID

事务指的是满足 ACID 特性的一组操作。可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。

  • 原子性(Atomicity)
    事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
    回滚可以用回滚日志(Undo Log)来实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可。

  • 一致性(Consistency)
    数据库在事务执行前后都保持一致性状态。指系统从一个正确的状态,迁移到另一个正确的状态。

  • 隔离性(Isolation)
    一个事务所做的修改在最终提交以前,对其它事务是不可见的。

  • 持久性(Durability)
    一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。
    系统发生奔溃可以用重做日志(Redo Log)进行恢复,从而实现持久性。与回滚日志记录数据的逻辑修改不同,重做日志记录的是数据页的物理修改。

并发一致性问题

  • 脏写:两事务先后对数据修改未提交,后修改会覆盖先修改。
  • 脏读:A事务修改数据未提交,B事务读,然后A事务回滚,导致B事务使用了错误数据。
  • 不可重复读:B事务读一数据,A事务update/delete未提交,B事务之后又读一次,发现前后读到的不一致。
  • 幻读:A事务调用count(*),B事务insert,A事务又调用count(*),发现多了几行数据。

隔离级别

  • 未提交读:事务可读取未提交的事务的修改。
  • 提交读:事务只可读取已提交的事务的修改。
  • 可重复度:保证同一事务多次读取同一数据的结果一致。
  • 可串行化:事务串行执行,互不干扰,永不出现并发一致性问题。

脏读:未提交读。
不可重复读:未提交读、提交读。
幻读:未提交读、提交读、可重复读。

封锁

封锁粒度:行锁、表锁。
封锁类型:读写锁、意向锁。

读锁(S)、写锁(X):给单位加读锁,不影响其他事务的加读锁,但不让加写锁;给单位加写锁,则不让其他事务加读写锁。

意向锁(IS、IX):事务想给表加写锁,就需要检测所有行是否有加写锁,这无疑很耗时。所以加入意向锁,当给行加写锁,需要给表加IX锁;给行加读锁,需要给表加IS锁

封锁协议:

一级:事务要修改必须加X锁,事务结束才可释放。解决脏写。
二级:事务要读取必须加S锁,读取完立马释放。解决脏读。
三级:事务要读取必须加S锁,事务结束才可释放。解决不可重复读。

多版本并发控制

实际场景中读操作往往多于写操作,而读写冲突会导致读等待。

MVCC利用多版本的思想,使写操作更新最新的版本快照,而读操作去读取旧版本快照,使互斥关系消失。

MVCC 规定只能读取已经提交的快照。

有快照生成,就代表有修改;读操作不会触发MVCC的任何改变。

当前读与快照读

当前读,像select lock in share mode(共享锁), select for update ; update, insert ,delete(排他锁),它读取的是记录的最新版本,会对读取的记录进行加锁。

快照读,不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读。

隐式字段

系统版本号SYS_ID是一个递增的数字,每开始一个新的事务,系统版本号就会自动递增。

每一行数据,都会多出三列(其中一列是无主键时自动生成的DB_ROW_ID):

  • 事务版本号 DB_TRX_ID :事务开始时的系统版本号。

  • 回滚指针 DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本(存储于rollback segment里)。

Undo日志

MVCC 的多版本快照存储在 Undo 日志中。

Undo日志通过回滚指针 ROLL_PTR 把一个数据行的所有快照连接起来。

Undo日志记录了记录事务版本号 TRX_ID 和数据,还记录了一个DEL 字段,用于标记是否被删除。

Undo日志有两种:

  • insert undo log:代表事务在insert新记录时产生的undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃。

  • update undo log:事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被统一清除。

ReadView

未提交读、可串行化这两个隔离级别,读取版本链中最新版本的记录即可,提交读、可重复读,就需要遍历所有快照,判断某个版本的记录是否对当前事务可见。InnoDB通过ReadView实现了这个功能。

ReadView存储所有未提交即活跃事务的版本号 TRX_IDs,和TRX_ID_MIN、TRX_ID_MAX。

在MySQL中,READ COMMITTED和REPEATABLE READ隔离级别的的一个非常大的区别就是它们生成ReadView的时机不同。READ COMMITTED在每次读取数据前都会生成一个ReadView,这样就能保证每次都能读到其它事务已提交的数据。REPEATABLE READ 只在第一次读取数据时生成一个ReadView,这样就能保证后续读取的结果完全一致。

在select时,先从最新版本快照开始,读取数据行快照的 TRX_ID并判断:

  • TRX_ID < TRX_ID_MIN,表示该数据行快照时在当前所有未提交事务之前进行更改的,因此可以使用。
  • TRX_ID > TRX_ID_MAX,表示生成该快照的事务在执行select的事务之后进行修改,因此不可使用,然后根据回滚指针到上一个版本继续判断。
  • TRX_ID_MIN <= TRX_ID <= TRX_ID_MAX,如果在TRX_IDs列表里,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。

范式

函数依赖:记 A->B 表示 A 函数决定 B,也可以说 B 函数依赖于 A。

第一范式:属性不可拆分。
第二范式:每个非主属性完全函数依赖于键码。(“完全”指当键码为多个组合的,不能让组合之一去函数决定一个非主属性,只能整个组合函数决定。可通过拆分解决)
第三范式:非主属性不传递函数依赖于键码。(只能由键码来决定所有的非主属性)

ER图

Entity-Relationship,有三个组成部分:实体、属性、联系。

实体的三种联系包含一对一,一对多,多对多三种。

  • 如果 A 到 B 是一对多关系,那么画个带箭头的线段指向 B;
  • 如果是一对一,画两个带箭头的线段;
  • 如果是多对多,画两个不带箭头的线段。

下图的 Course 和 Student 是一对多的关系。
在这里插入图片描述

表示出现多次的关系:一个实体在联系出现几次,就要用几条线连接。

下图表示一个课程的先修关系,先修关系出现两个 Course 实体,第一个是先修课程,后一个是后修课程,因此需要用两条线来表示这种关系。
在这里插入图片描述

联系的多向性:虽然老师可以开设多门课,并且可以教授多名学生,但是对于特定的学生和课程,只有一个老师教授,这就构成了一个三元联系。
在这里插入图片描述

表示子类:用一个三角形和两条线来连接类和子类,与子类有关的属性和联系都连到子类上,而与父类和子类都有关的连到父类上。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值