部分内容参考自JavaGuide Mysql
文章目录
一 概述
名词解释
DBMS:数据库管理系统
DBA:数据库管理员
redundancy:冗余
inconsistency:不一致性
integrity:完整性
constraint:约束
atomicity:原子性
concurrent:并发
instance:实例
schema:模式
relation:关系
tuple:元组
entity:实体
SQL:结构化查询语言
DDL:数据定义语言
DML:数据操控语言
transaction:事务
metadata:元数据
关系模型
一个关系对应一张表,一个元组/记录对应一行,一个属性对应一列
二 关系模型
基本介绍
属性域:属性允许的取值范围,取值具有原子性即不可划分
元组是没有顺序的
码/键
超码super key:可以确定关系的唯一一个元组的属性或属性集合
候选码candidate key:最小的超码,候选码的子集不能是超码
主码primary key:其中一个候选码被选为主码
外码foreign key:参照或被参照的属性
关系代数
元组选择
投影
笛卡尔积
并
差
交
并、差、交需要满足:相同属性个数、相同属性名、相同属性域
自然连接
三 SQL
MYSQL命令
见”MySQL命令大全.md"
四 实体联系模型
简介
实体是对象,实体具有属性,实体之间产生联系,联系也可以有属性
属性
域:属性的取值范围
分类
- 简单属性和复合属性(可以细分,比如地址)
- 单值属性和多值属性(多种含义,比如手机号)
- 推导属性(可以由其它属性计算得出,比如年龄)
映射的势
- 一对一
- 一对多
- 多对一
- 多对多
E-R图特征
矩形-实体(带属性列表)
菱形-联系 双菱形-依赖关系
带实下划线的属性-主码
带虚下划线的属性-区分符
缩进的属性-复合属性
被{}包含的属性-多值属性
带()的属性-推导属性
有箭头的线-一的关系
无箭头的线-多的关系
单线-部分参与
双线-完全参与(每个实体都至少参与一个联系)
强实体集
弱实体集(没有主码,需要依赖强实体集)
实体建模
强实体集建模:与原本一样
弱实体集建模:主码=弱实体集的区分符+依赖强实体集的主码
联系建模
多对多联系:主码是联系的实体集的主码合起来,有几个联系的实体集就有几个外码
一对多、一对一联系:可建模可不建模
依赖关系:不建模
五 关系数据库设计
名词解释
decompose 分解
functional dependency 函数依赖
lossy decomposition 有损分解
lossless join decomposition 无损连接分解
normal form 范式
1NF
域是原子性的,即不可细分
函数依赖
a,b是关系R的属性集合
a->b:a函数决定b或者b函数依赖于a(在R中任意两行在a的值相同则这两行在b的值也相同)
K->R,则K是超码
K->R,K的子集都不是超码,则K是候选码
主属性:候选码的属性
依赖保持:每个函数依赖都保持在单个关系上
2NF
不存在非主属性对候选码的部分依赖,即非主属性完全依赖候选码
BCNF
对于所有函数依赖,至少满足一个条件:1 a->b是平凡的;2 a是R的超码
BCNF分解
对不满足BCNF的函数依赖分解为a并b, R-(b-a)
3NF
对于所有函数依赖,至少满足一个条件:1 a->b是平凡的;2 a是R的超码;3 b-a的每个属性包含在一个候选码中
3NF分解
对正则覆盖合并依赖左右两边,注意有一个关系要包含一个候选码
公理与定理
正则覆盖
不存在多余的依赖或属性
所有依赖的左边唯一
F1是F2的正则覆盖,则F1可推导出F2,F2可推导出F1
无损连接分解
R分解为R1,R2,R1交R2的公共属性决定R1或者R2
六 事务
简介
逻辑上的一组操作,要么都执行,要么都不执行
ACID特性
原子性Atomicity:事务的原子性确保动作要么全部完成,要么完全不起作用
一致性Consistency:执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的
隔离性Isolation:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的
持久性Durability:一个事务被提交之后,对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响
事务状态
可串行化
分类
冲突可串行化
视图可串行化
冲突指令
read(Q), read(Q):不冲突
read(Q), write(Q):冲突
write(Q), read(Q):冲突
write(Q), write(Q):冲突
冲突等价
一个并行调度S交换非冲突指令后得到串行调度S‘,则两个调度是冲突等价的,S是冲突可串行化的
判断是否冲突可串行化
优先图
边集由满足以下三个条件之一的边Ti->Tj组成
- Ti read(Q)后Tj write(Q)
- Ti write(Q)后Tj read(Q)
- Ti write(Q)后Tj write(Q)
如果优先图出现回路,则这个调度不是冲突可串行化的
可恢复调度
如果Ti write(Q)后Tj read(Q),则Ti 应该先提交,Tj后提交
操作
MySQL默认情况下,事务是自动提交的,只要执行一条DML语句就开启并提交了事务
要显式地开启一个事务需要使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交
具体见”MySQL命令大全.md"事务部分
实现原理
以 MySQL 的 InnoDB 引擎为例
MySQL InnoDB 引擎使用 redo log(重做日志) 保证事务的持久性,使用 undo log(回滚日志) 来保证事务的原子性。
MySQL InnoDB 引擎通过 锁机制、MVCC 等手段来保证事务的隔离性( 默认支持的隔离级别是 REPEATABLE-READ
)。
保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障。
并发事务带来的问题
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对同一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。
- 脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
- 丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务 1 读取某表中的数据 A=20,事务 2 也读取 A=20,事务 1 修改 A=A-1,事务 2 也修改 A=A-1,最终结果 A=19,事务 1 的修改被丢失。
- 不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
- 幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
不可重复读和幻读区别:
不可重复读的重点是修改比如多次读取一条记录发现其中某些列的值被修改,幻读的重点在于新增或者删除比如多次读取一条记录发现记录增多或减少了。
事务隔离级别
SQL 标准定义了四个隔离级别:
- READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- SERIALIZABLE(可串行化): 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITTED | × | √ | √ |
REPEATABLE-READ | × | × | √ |
SERIALIZABLE | × | × | × |
MySQL 的默认隔离级别
MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。我们可以通过SELECT @@tx_isolation;
命令来查看,MySQL 8.0 该命令改为SELECT @@transaction_isolation;
MySQL InnoDB 的 REPEATABLE-READ(可重读)并不保证避免幻读,需要应用使用加锁读来保证。而这个加锁度使用到的机制就是 Next-Key Locks。
因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是 READ-COMMITTED(读取提交内容) ,但是你要知道的是 InnoDB 存储引擎默认使用 REPEAaTABLE-READ(可重读) 并不会有任何性能损失。
InnoDB 存储引擎在 分布式事务 的情况下一般会用到 SERIALIZABLE(可串行化) 隔离级别。