文章目录
参考
CyC2018/CS-Notes
详解第一范式、第二范式、第三范式、BCNF范式
事务
1. 概念
- 事务时满足
ACID
特性的一组操作
,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。
2. 四大特性
- 原子性
事务被视为不可分割
的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚
。 - 一致性
数据库在事务执行前后都保持一致性状态
。在一致性状态下,所有事务对一个数据的读取结果都是相同的。(不能有事务读取到旧数据,所有事务对同一数据的读取保持一致) - 隔离性
一个事务所做的修改在最终提交以前,对其它事务是不可见
的.(对用户来说,一个事务执行,不需要考虑其他事务正在并发执行) - 持久性
一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失
。
3. ACID关系
- 一个数据库系统需要保证
一致性
(执行结果正确),持久性
(数据不丢失) 一致性
需要靠原子性
和隔离性
来保证- 无并发时,事务串行执行,此时需要满足
原子性
- 有并发时,
原子性
和隔离性
都要保证
并发一致性问题
- 在存在并发的情况下,数据库需要解决事务的
隔离性
,从而保证一致性,如果没有保证,那么会出现下面的一些问题
1. 修改丢失
- T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。
- 这里T1和T2的隔离性没有保证,在T1看来,产生了错误的结果
2. 脏读
- T1修改数据,T2读数据,T1继续修改数据,那么T2读的是脏数据
- 这里T2在T1的事务还没结束,就读取到了中间数据
3. 不可重复读
- 由于T1的修改导致T2两次读取结果不同
4. 幻影读
- 跟不可重复读类似,幻影读针对范围内数据
- T2在T1统计时插入了新数据
那么如何解决上述问题?
显然需要并发控制,即`加锁`,如果用户自己加锁可能比较复杂,数据库系统提供了事务的`隔离级别`,让用户处理并发一致性问题更简单。
锁
1. 锁粒度
表级锁
和行级锁
- 表级锁锁定的数据量
多
,锁争用可能性大
,系统的并发程度低
,系统开销小
- 行级锁锁定的数据量
少
,锁争用可能性小
,系统的并发程度高
,系统开销大
锁定的数据量 | 锁数量 | 并发程度 | 系统开销 | |
---|---|---|---|---|
表级锁 | 多 | 少 | 低 | 小 |
行级锁 | 少 | 多 | 高 | 大 |
- 因此需要在
锁粒度
和并发程度
做权衡
2. 锁类型
- 读写锁
- 排它锁(Exlusive,X锁,
写锁
),可以读写 - 共享锁(Shared,S锁,
读锁
),只能读 - 事务T1对A加写锁,事务T2不能对A加锁
- T1对A加S锁,T2可以对A加S锁,不能加X锁
- 意向锁
- 读写锁的问题:如果T1需要对表A加表的写锁,那么需要检测是否有其他事务对表A的任意一行加了锁,这是非常耗时的。
- IX锁:写表的意向锁
- IS锁:读表的意向锁
- 事务在获取行的S锁之前,需要获取表的IS锁或更强的锁
- 事务在获取行的X锁之前,需要先获取表的IX锁
意向锁
主要是对整表加锁
使用的
锁协议
1. 三级锁协议
- 一级锁协议
T修改A时加X锁,T结束后释放锁
可以解决修改丢失
问题 - 二级锁协议
读加S锁,读完后立即释放S锁
解决读脏数据
问题 - 三级锁协议
读加S锁,事务结束后释放S锁
解决不可重复读
问题
2. 两段锁协议
- 事务分为加锁和解锁两个阶段进行,在读写时都需要获取锁,如果未能获取锁,则等待,以便保证可串行化调度
- 如
lock-x(A)...lock-s(B)...lock-s(C)...unlock(A)...unlock(C)...unlock(B)
3.MySQL隐式与显示锁定
- MySQL的InnoDB引擎使用两段锁协议,会根据隔离级别在需要的时候自动加锁,并且所有锁在同一时刻被释放,即
隐式锁定
- 在SQL语句中,可以指定
显示锁定
SELECT ... LOCK IN SHARE MODE;# S锁
SELECT ... FOR UPDATE; # X锁
隔离级别
- 从低到高依次为
1. 未提交读
- 事务的修改在提交前对其他事务可见
- 没有隔离,会造成
脏读、不可重复读、幻影读
2. 提交读
- 事务的修改在提交前对其他事物不可见
- 不会造成脏读,但会造成
不可重复读
,幻影读。(如T1读取数据A→T2的事务修改A并提交→T1再次读取数据A)
3. 可重读读
- 保证同一个事务多次读取同样数据的结果一样
- 未解决
幻影读
4. 可串行化
- 强制事务串行执行,需要加锁实现
- 不会存在并发一致性问题
MySQL的隔离级别实现
- InnoDB采用
多版本并发控制(MVCC)
来实现提交读和可重复读
这两种隔离级别 - InnoDB采用
Next-Key Locks
实现加锁机制 - 用MVCC的可重复读+Next-Key Locks可以解决
幻影读
问题
关系数据库理论
1. 函数依赖
- A → B表示A决定B或B依赖于A(通俗讲 : 知道A就知道B)
键码
: 能够决定其他所有属性的最小属性集合- 对于 A->B,如果能找到 A 的真子集 A’,使得 A’-> B,那么 A->B 就是
部分函数依赖
(B可以依赖于A的一部分),否则就是完全函数依赖
(B完全依赖于A)。 - 如果 A->B,B->C,则 A->C 是一个传递函数依赖。
2. 异常
- 不符合范式的关系会产生异常
- 冗余异常、修改异常、删除异常、插入异常
3. 范式
- 定义:符合某一种级别的关系模式的集合,表示一个关系内部
各属性之间的联系的合理化程度
- 数据库范式也分为1NF,2NF,3NF,BCNF,4NF,5NF。一般在我们设计关系型数据库的时候,最多考虑到BCNF就够。
符合高一级范式的设计,必定符合低一级范式
,例如符合2NF的关系模式,必定符合1NF。
3.1 1NF
- 关系中每个
属性不可再分
- 例:
- 这个关系不符合1NF,需要修改为
- 此时每个属性不可再分,满足1NF
3.2 2NF
- 每个非主属性完全函数依赖于键码
- 例:
- 这个关系中的函数依赖关系为:
{Sno, Cname} -> {Sname, Sdept, Mname, Grade} - 其中每个非主属性只是部分依赖于键码如Sname只依赖于Sno,因此不符合2NF
- 可以通过
分解
的方法使其满足2NF - 关系可以分解为
Sno -> Sname, Sdept,Mname
Sno, Cname-> Grade
- 此时每个非主属性就完全依赖于键码了,满足2NF
3.3 3NF
非主属性
中禁止传递函数依赖- 在2NF的例子中
Sno -> Sname, Sdept,Mname
- 而实际上,Mname是依赖于Sdept
- 因此存在传递函数依赖
Sno -> Sdept -> Mname
- 可以分解为
Sno -> Sname, Sdept
Sdept -> Mname
- 这样即满足3NF
ER图
假设教学管理规定:
一个学生可选修多门课,一门课有若干学生选修;
一个教师可讲授多门课,一门课只有一个教师讲授;
一个学生选修一门课,仅有一个成绩。
学生的属性有学号、学生姓名;教师的属性有教师编号,教师姓名;课程的属性有课程号、课程名。
要求:根据上述语义画出ER 图,要求在图中画出实体的属性并注明联系的类型。