auto commit

This commit is contained in:
CyC2018
2020-11-17 00:32:18 +08:00
parent f5ad47b470
commit 7e61fc1360
380 changed files with 2371 additions and 46715 deletions

View File

@ -1,71 +1,43 @@
# 数据库系统原理
<!-- GFM-TOC -->
* [事务](#一事务)
* [概念](#概念)
* [ACID](#acid)
* [AUTOCOMMIT](#autocommit)
* [并发一致性问题](#二并发一致性问题)
* [丢失修改](#丢失修改)
* [读脏数据](#读脏数据)
* [不可重复读](#不可重复读)
* [幻影读](#幻影读)
* [封锁](#三封锁)
* [封锁粒度](#封锁粒度)
* [封锁类型](#封锁类型)
* [封锁协议](#封锁协议)
* [MySQL 隐式与显示锁定](#mysql-隐式与显示锁定)
* [隔离级别](#四隔离级别)
* [未提交读READ UNCOMMITTED](#未提交读read-uncommitted)
* [提交读READ COMMITTED](#提交读read-committed)
* [可重复读REPEATABLE READ](#可重复读repeatable-read)
* [可串行化SERIALIZABLE](#可串行化serializable)
* [多版本并发控制](#五多版本并发控制)
* [基本思想](#基本思想)
* [版本号](#版本号)
* [Undo 日志](#undo-日志)
* [ReadView](#readview)
* [快照读与当前读](#快照读与当前读)
* [Next-Key Locks](#六next-key-locks)
* [Record Locks](#record-locks)
* [Gap Locks](#gap-locks)
* [Next-Key Locks](#next-key-locks)
* [关系数据库设计理论](#七关系数据库设计理论)
* [函数依赖](#函数依赖)
* [异常](#异常)
* [范式](#范式)
* [ER ](#八er-)
* [实体的三种联系](#实体的三种联系)
* [表示出现多次的关系](#表示出现多次的关系)
* [联系的多向性](#联系的多向性)
* [表示子类](#表示子类)
* [参考资料](#参考资料)
* [数据库系统原理](#数据库系统原理)
* [事务](#一事务)
* [并发一致性问题](#二并发一致性问题)
* [封锁](#三封锁)
* [隔离级别](#四隔离级别)
* [多版本并发控制](#五多版本并发控制)
* [Next-Key Locks](#六next-key-locks)
* [关系数据库设计理论](#七关系数据库设计理论)
* [ER ](#八er-)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# 事务
## 事务
## 概念
### 概念
事务指的是满足 ACID 特性的一组操作可以通过 Commit 提交一个事务也可以使用 Rollback 进行回滚
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207222237925.png"/> </div><br>
## ACID
### ACID
### 1. 原子性Atomicity
#### 1. 原子性Atomicity
事务被视为不可分割的最小单元事务的所有操作要么全部提交成功要么全部失败回滚
回滚可以用回滚日志Undo Log来实现回滚日志记录着事务所执行的修改操作在回滚时反向执行这些修改操作即可
### 2. 一致性Consistency
#### 2. 一致性Consistency
数据库在事务执行前后都保持一致性状态在一致性状态下所有事务对同一个数据的读取结果都是相同的
### 3. 隔离性Isolation
#### 3. 隔离性Isolation
一个事务所做的修改在最终提交以前对其它事务是不可见的
### 4. 持久性Durability
#### 4. 持久性Durability
一旦事务提交则其所做的修改将会永远保存到数据库中即使系统发生崩溃事务执行的结果也不能丢失
@ -82,33 +54,33 @@
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207210437023.png"/> </div><br>
## AUTOCOMMIT
### AUTOCOMMIT
MySQL 默认采用自动提交模式也就是说如果不显式使用`START TRANSACTION`语句来开始一个事务那么每个查询操作都会被当做一个事务并自动提交
# 并发一致性问题
## 并发一致性问题
在并发环境下事务的隔离性很难保证因此会出现很多并发一致性问题
## 丢失修改
### 丢失修改
丢失修改指一个事务的更新操作被另外一个事务的更新操作替换一般在现实生活中常会遇到例如T<sub>1</sub> T<sub>2</sub> 两个事务都对一个数据进行修改T<sub>1</sub> 先修改并提交生效T<sub>2</sub> 随后修改T<sub>2</sub> 的修改覆盖了 T<sub>1</sub> 的修改
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207221744244.png"/> </div><br>
## 读脏数据
### 读脏数据
读脏数据指在不同的事务下当前事务可以读到另外事务未提交的数据例如T<sub>1</sub> 修改一个数据但未提交T<sub>2</sub> 随后读取这个数据如果 T<sub>1</sub> 撤销了这次修改那么 T<sub>2</sub> 读取的数据是脏数据
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207221920368.png"/> </div><br>
## 不可重复读
### 不可重复读
不可重复读指在一个事务内多次读取同一数据集合在这一事务还未结束前另一事务也访问了该同一数据集合并做了修改由于第二个事务的修改第一次事务的两次读取的数据可能不一致例如T<sub>2</sub> 读取一个数据T<sub>1</sub> 对该数据做了修改如果 T<sub>2</sub> 再次读取这个数据此时读取的结果和第一次读取的结果不同
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207222102010.png"/> </div><br>
## 幻影读
### 幻影读
幻读本质上也属于不可重复读的情况T<sub>1</sub> 读取某个范围的数据T<sub>2</sub> 在这个范围内插入新的数据T<sub>1</sub> 再次读取这个范围的数据此时读取的结果和和第一次读取的结果不同
@ -118,9 +90,9 @@ MySQL 默认采用自动提交模式。也就是说,如果不显式使用`STAR
产生并发不一致性问题的主要原因是破坏了事务的隔离性解决方法是通过并发控制来保证隔离性并发控制可以通过封锁来实现但是封锁操作需要用户自己控制相当复杂数据库管理系统提供了事务的隔离级别让用户以一种更轻松的方式处理并发一致性问题
# 封锁
## 封锁
## 封锁粒度
### 封锁粒度
MySQL 中提供了两种封锁粒度行级锁以及表级锁
@ -131,9 +103,9 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
在选择封锁粒度时需要在锁开销和并发程度之间做一个权衡
## 封锁类型
### 封锁类型
### 1. 读写锁
#### 1. 读写锁
- 互斥锁Exclusive简写为 X 又称写锁
- 共享锁Shared简写为 S 又称读锁
@ -147,7 +119,7 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207213523777.png"/> </div><br>
### 2. 意向锁
#### 2. 意向锁
使用意向锁Intention Locks可以更容易地支持多粒度封锁
@ -169,9 +141,9 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
- 任意 IS/IX 锁之间都是兼容的因为它们只表示想要对表加锁而不是真正加锁
- 这里兼容关系针对的是表级锁而表级的 IX 锁和行级的 X 锁兼容两个事务可以对两个数据行加 X 事务 T<sub>1</sub> 想要对数据行 R<sub>1</sub> X 事务 T<sub>2</sub> 想要对同一个表的数据行 R<sub>2</sub> X 两个事务都需要对该表加 IX 但是 IX 锁是兼容的并且 IX 锁与行级的 X 锁也是兼容的因此两个事务都能加锁成功对同一个表中的两个数据行做修改
## 封锁协议
### 封锁协议
### 1. 三级封锁协议
#### 1. 三级封锁协议
**一级封锁协议**
@ -197,7 +169,7 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207221313819.png"/> </div><br>
### 2. 两段锁协议
#### 2. 两段锁协议
加锁和解锁分为两个阶段进行
@ -215,7 +187,7 @@ lock-x(A)...lock-s(B)...lock-s(C)...unlock(A)...unlock(C)...unlock(B)
lock-x(A)...unlock(A)...lock-s(B)...unlock(B)...lock-s(C)...unlock(C)
```
## MySQL 隐式与显示锁定
### MySQL 隐式与显示锁定
MySQL InnoDB 存储引擎采用两段锁协议会根据隔离级别在需要的时候自动加锁并且所有的锁都是在同一时刻被释放这被称为隐式锁定
@ -226,21 +198,21 @@ SELECT ... LOCK In SHARE MODE;
SELECT ... FOR UPDATE;
```
# 隔离级别
## 隔离级别
## 未提交读READ UNCOMMITTED
### 未提交读READ UNCOMMITTED
事务中的修改即使没有提交对其它事务也是可见的
## 提交读READ COMMITTED
### 提交读READ COMMITTED
一个事务只能读取已经提交的事务所做的修改换句话说一个事务所做的修改在提交之前对其它事务是不可见的
## 可重复读REPEATABLE READ
### 可重复读REPEATABLE READ
保证在同一个事务中多次读取同一数据的结果是一样的
## 可串行化SERIALIZABLE
### 可串行化SERIALIZABLE
强制事务串行执行这样多个事务互不干扰不会出现并发一致性问题
@ -250,11 +222,11 @@ SELECT ... FOR UPDATE;
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207223400787.png"/> </div><br>
# 多版本并发控制
## 多版本并发控制
多版本并发控制Multi-Version Concurrency Control, MVCC MySQL InnoDB 存储引擎实现隔离级别的一种具体方式用于实现提交读和可重复读这两种隔离级别而未提交读隔离级别总是读取最新的数据行要求很低无需使用 MVCC可串行化隔离级别需要对所有读取的行都加锁单纯使用 MVCC 无法实现
## 基本思想
### 基本思想
在封锁一节中提到加锁能解决多个事务同时执行时出现的并发一致性问题在实际场景中读操作往往多于写操作因此又引入了读写锁来避免不必要的加锁操作例如读和读没有互斥关系读写锁中读和写操作仍然是互斥的 MVCC 利用了多版本的思想写操作更新最新的版本快照而读操作去读旧版本快照没有互斥关系这一点和 CopyOnWrite 类似
@ -262,12 +234,12 @@ SELECT ... FOR UPDATE;
脏读和不可重复读最根本的原因是事务读取到其它事务未提交的修改在事务进行读取操作时为了解决脏读和不可重复读问题MVCC 规定只能读取已经提交的快照当然一个事务可以读取自身未提交的快照这不算是脏读
## 版本号
### 版本号
- 系统版本号 SYS_ID是一个递增的数字每开始一个新的事务系统版本号就会自动递增
- 事务版本号 TRX_ID 事务开始时的系统版本号
## Undo 日志
### Undo 日志
MVCC 的多版本指的是多个版本的快照快照存储在 Undo 日志中该日志通过回滚指针 ROLL_PTR 把一个数据行的所有快照连接起来
@ -285,7 +257,7 @@ UPDATE t SET x="c" WHERE id=1;
INSERTUPDATEDELETE 操作会创建一个日志并将事务版本号 TRX_ID 写入DELETE 可以看成是一个特殊的 UPDATE还会额外将 DEL 字段设置为 1
## ReadView
### ReadView
MVCC 维护了一个 ReadView 结构主要包含了当前系统未提交的事务列表 TRX_IDs {TRX_ID_1, TRX_ID_2, ...}还有该列表的最小值 TRX_ID_MIN TRX_ID_MAX
@ -293,18 +265,18 @@ MVCC 维护了一个 ReadView 结构,主要包含了当前系统未提交的
在进行 SELECT 操作时根据数据行快照的 TRX_ID TRX_ID_MIN TRX_ID_MAX 之间的关系从而判断数据行快照是否可以使用
- TRX_ID < TRX_ID_MIN表示该数据行快照时在当前所有未提交事务之前进行更改的因此可以使用
- TRX_ID \< TRX_ID_MIN表示该数据行快照时在当前所有未提交事务之前进行更改的因此可以使用
- TRX_ID > TRX_ID_MAX表示该数据行快照是在事务启动之后被更改的因此不可使用
- TRX_ID_MIN <= TRX_ID <= TRX_ID_MAX需要根据隔离级别再进行判断
- TRX_ID \> TRX_ID_MAX表示该数据行快照是在事务启动之后被更改的因此不可使用
- TRX_ID_MIN \<= TRX_ID \<= TRX_ID_MAX需要根据隔离级别再进行判断
- 提交读如果 TRX_ID TRX_IDs 列表中表示该数据行快照对应的事务还未提交则该快照不可使用否则表示已经提交可以使用
- 可重复读都不可以使用因为如果可以使用的话那么其它事务也可以读到这个数据行快照并进行修改那么当前事务再去读这个数据行得到的值就会发生改变也就是出现了不可重复读问题
在数据行快照不可使用的情况下需要沿着 Undo Log 的回滚指针 ROLL_PTR 找到下一个快照再进行上面的判断
## 快照读与当前读
### 快照读与当前读
### 1. 快照读
#### 1. 快照读
MVCC SELECT 操作是快照中的数据不需要进行加锁操作
@ -312,7 +284,7 @@ MVCC 的 SELECT 操作是快照中的数据,不需要进行加锁操作。
SELECT * FROM table ...;
```
### 2. 当前读
#### 2. 当前读
MVCC 其它会对数据库进行修改的操作INSERTUPDATEDELETE需要进行加锁操作从而读取最新的数据可以看到 MVCC 并不是完全不用加锁而只是避免了 SELECT 的加锁操作
@ -329,19 +301,19 @@ SELECT * FROM table WHERE ? lock in share mode;
SELECT * FROM table WHERE ? for update;
```
# Next-Key Locks
## Next-Key Locks
Next-Key Locks MySQL InnoDB 存储引擎的一种锁实现
MVCC 不能解决幻影读问题Next-Key Locks 就是为了解决这个问题而存在的在可重复读REPEATABLE READ隔离级别下使用 MVCC + Next-Key Locks 可以解决幻读问题
## Record Locks
### Record Locks
锁定一个记录上的索引而不是记录本身
如果表没有设置索引InnoDB 会自动在主键上创建隐藏的聚簇索引因此 Record Locks 依然可以使用
## Gap Locks
### Gap Locks
锁定索引之间的间隙但是不包含索引本身例如当一个事务执行以下语句其它事务就不能在 t.c 中插入 15
@ -349,7 +321,7 @@ MVCC 不能解决幻影读问题Next-Key Locks 就是为了解决这个问题
SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
```
## Next-Key Locks
### Next-Key Locks
它是 Record Locks Gap Locks 的结合不仅锁定一个记录上的索引也锁定索引之间的间隙它锁定一个前开后闭区间例如一个索引包含以下值10, 11, 13, and 20那么就需要锁定以下区间
@ -361,21 +333,21 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
(20, +)
```
# 关系数据库设计理论
## 关系数据库设计理论
## 函数依赖
### 函数依赖
A->B 表示 A 函数决定 B也可以说 B 函数依赖于 A
A-\>B 表示 A 函数决定 B也可以说 B 函数依赖于 A
如果 {A1A2... An} 是关系的一个或多个属性的集合该集合函数决定了关系的其它所有属性并且是最小的那么该集合就称为键码
对于 A->B如果能找到 A 的真子集 A'使得 A'-> B那么 A->B 就是部分函数依赖否则就是完全函数依赖
对于 A-\>B如果能找到 A 的真子集 A'使得 A'-\> B那么 A-\>B 就是部分函数依赖否则就是完全函数依赖
对于 A->BB->C A->C 是一个传递函数依赖
对于 A-\>BB-\>C A-\>C 是一个传递函数依赖
## 异常
### 异常
以下的学生课程关系的函数依赖为 {Sno, Cname} -> {Sname, Sdept, Mname, Grade}键码为 {Sno, Cname}也就是说确定学生和课程之后就能确定其它信息
以下的学生课程关系的函数依赖为 {Sno, Cname} -\> {Sname, Sdept, Mname, Grade}键码为 {Sno, Cname}也就是说确定学生和课程之后就能确定其它信息
| Sno | Sname | Sdept | Mname | Cname | Grade |
| :---: | :---: | :---: | :---: | :---: |:---:|
@ -391,17 +363,17 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
- 删除异常删除一个信息那么也会丢失其它信息例如删除了 `课程-1` 需要删除第一行和第三行那么 `学生-1` 的信息就会丢失
- 插入异常例如想要插入一个学生的信息如果这个学生还没选课那么就无法插入
## 范式
### 范式
范式理论是为了解决以上提到四种异常
高级别范式的依赖于低级别的范式1NF 是最低级别的范式
### 1. 第一范式 (1NF)
#### 1. 第一范式 (1NF)
属性不可分
### 2. 第二范式 (2NF)
#### 2. 第二范式 (2NF)
每个非主属性完全函数依赖于键码
@ -418,9 +390,9 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
以上学生课程关系中{Sno, Cname} 为键码有如下函数依赖
- Sno -> Sname, Sdept
- Sdept -> Mname
- Sno, Cname-> Grade
- Sno -\> Sname, Sdept
- Sdept -\> Mname
- Sno, Cname-\> Grade
Grade 完全函数依赖于键码它没有任何冗余数据每个学生的每门课都有特定的成绩
@ -438,8 +410,8 @@ Sname, Sdept 和 Mname 都部分依赖于键码,当一个学生选修了多门
有以下函数依赖
- Sno -> Sname, Sdept
- Sdept -> Mname
- Sno -\> Sname, Sdept
- Sdept -\> Mname
关系-2
@ -452,15 +424,15 @@ Sname, Sdept 和 Mname 都部分依赖于键码,当一个学生选修了多门
有以下函数依赖
- Sno, Cname -> Grade
- Sno, Cname -\> Grade
### 3. 第三范式 (3NF)
#### 3. 第三范式 (3NF)
非主属性不传递函数依赖于键码
上面的 关系-1 中存在以下传递函数依赖
- Sno -> Sdept -> Mname
- Sno -\> Sdept -\> Mname
可以进行以下分解
@ -479,13 +451,13 @@ Sname, Sdept 和 Mname 都部分依赖于键码,当一个学生选修了多门
| 学院-1 | 院长-1 |
| 学院-2 | 院长-2 |
# ER
## ER
Entity-Relationship有三个组成部分实体属性联系
用来进行关系型数据库系统的概念设计
## 实体的三种联系
### 实体的三种联系
包含一对一一对多多对多三种
@ -497,7 +469,7 @@ Entity-Relationship有三个组成部分实体、属性、联系。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1d28ad05-39e5-49a2-a6a1-a6f496adba6a.png" width="380px"/> </div><br>
## 表示出现多次的关系
### 表示出现多次的关系
一个实体在联系出现几次就要用几条线连接
@ -505,19 +477,19 @@ Entity-Relationship有三个组成部分实体、属性、联系。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ac929ea3-daca-40ec-9e95-4b2fa6678243.png" width="250px"/> </div><br>
## 联系的多向性
### 联系的多向性
虽然老师可以开设多门课并且可以教授多名学生但是对于特定的学生和课程只有一个老师教授这就构成了一个三元联系
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/5bb1b38a-527e-4802-a385-267dadbd30ba.png" width="350px"/> </div><br>
## 表示子类
### 表示子类
用一个三角形和两条线来连接类和子类与子类有关的属性和联系都连到子类上而与父类和子类都有关的连到父类上
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/14389ea4-8d96-4e96-9f76-564ca3324c1e.png" width="450px"/> </div><br>
# 参考资料
## 参考资料
- AbrahamSilberschatz, HenryF.Korth, S.Sudarshan, . 数据库系统概念 [M]. 机械工业出版社, 2006.
- 施瓦茨. 高性能 MYSQL(第3版)[M]. 电子工业出版社, 2013.
@ -531,10 +503,3 @@ Entity-Relationship有三个组成部分实体、属性、联系。
- [MySQL locking for the busy web developer](https://www.brightbox.com/blog/2013/10/31/on-mysql-locks/)
- [浅入浅出 MySQL InnoDB](https://draveness.me/mysql-innodb)
- [Innodb 中的事务隔离级别和锁的关系](https://tech.meituan.com/2014/08/20/innodb-lock.html)
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-2.png"></img></div>