目录
一、事务
1.概念
2.事务的特性
3.并发带来的问题
4.事务的隔离级别
二、锁机制
1.什么是锁
2.MySQL锁分类
3.乐观悲观锁
4.共享排它锁
5.意向锁
6.粒度锁
三、三大范式
1.第一范式
2.第二范式
3.第三范式
一、事务
1.概念
事务是逻辑上的一组操作,要么全执行,要么全不执行。
事务最经典栗子也经常被拿出来的栗子就是银行转账了。比如小明要给小红转账1000元,这个转账会涉及到两个关键操作:将小明的余额减1000元,将小红的余额减1000元。万一这两个操作之间突然出现错误,导致小明余额减少但是小红余额没有增加,这种情况是肯定不允许的。事务就是保证这两个关键操作要么都成功,要么都不成功。
2.事务的特性
①原子性
是事务的最小执行单位,不允许再分割。
②一致性
执行事务前后,数据保持一致。
③隔离性
并发访问数据库时,一个用户的事务不应该被其他事务影响,所有并发事务之间数据库是独立的。
④持久性
事务的提交对数据库数据的修改是永久的,即使数据库发生故障也不应该对其有所影响。
3.并发带来的问题
①脏读
当一个事务正在访问数据库时,并对数据进行了修改,但是事务还没有提交。这是另一个事务访问数据库时读取的数据就是“脏数据”。
②修改丢失
当两个事务同时访问同一个数据时,第一个事务将数据进行了修改,另一个事务也将读取到的数据进行修改,第一个事务做出的修改结果就会被丢失。
eg:一个数据为20,两个事务同时读取并做出修改(20-1),两个事务执行完的结果都为19,理想的结果应为依次减一,结果应为18.
③不可重复读
当一个事务需要频繁读取一个数据,在未提交时另一个事务读取数据并做出修改,那么第一个事务前后读取的结果就不一致,有可能造成结果错误。
④幻读
当一个事务读取数据库的5行数据时,在未提交的过程中另一个事务向这五行中新插入了一行新数据,那么第一个事务再次读取时数据发生了变化。
4.事务的隔离级别
①读未提交
最低的隔离级别,允许读取尚未提交的数据变更。脏读是在一个事务未提交时另一个事务读取发生的错误,所以不能避免。读未提交并不能避免不可重复读和幻读。
②读已提交
允许读取并发事务已经提交的数据,可以避免脏读,仍然不能解决不可重复读和幻读的问题。
③不可重复读
对同一个字段多次读取的结果都是一致的,除非本身事务发生了修改。可以避免脏读和不可重复读。
④可串行化
最高的隔离级别,完全服从ACID的隔离级别,所有事务依次执行,可以避免脏读、不可重复读、幻读。
二、锁机制
1.什么是锁
锁是计算机用以协调多个进程间并发访问同一共享资源的一种机制,解决并发事务的访问问题。
当一个事务进行读操作,另一个事务进行写操作,为了避免并发出现的问题,可以给读写操作都加锁。
2.MySQL锁分类
3.乐观悲观锁
3.1乐观锁
假设不会发生并发冲突,只在提交时检查是否违反了数据完整性,在修改数据时把事务锁起来通过版本控制的方式进行锁定。
3.2悲观锁
假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作,在查询完数据后就把事务锁起来,直到提交事务。
4.共享排它锁
4.1共享锁(读锁/S锁)
允许多个事务同时读取一张表,但是不能进行写操作。如果一个事务持有共享锁,其他事务也能持有共享锁,共享锁之间不会互相阻塞。
4.2排它锁(写锁/X锁)
只允许一个事务进行写操作,其他事务不能进行读取和写入操作。如果一个事务持有排它锁,其他事务无法获取共享锁和排它锁,排它锁会阻塞其他事务的读写操作。
5.意向锁
5.1意向共享锁(IS锁)
事务有意向对表中的某些记录加共享锁(S锁),加共享锁之前必须获取该表的IS锁。
5.2意向排它锁(IX锁)
事务有意向对表中的某些记录加排他锁(X锁),加排他锁之前必须获取该表的IX锁。
5.3兼容性
6.粒度锁
6.1全局锁
全局锁,从名称上可以理解,全局锁就是对整个 MySQL 数据库实例加锁,加锁期间,对数据库的任何增删改操作都无法执行,会阻塞所有对数据库的操作。
全库数据备份,可以使用全局锁,其他情况不要使用
MySQL 全局读锁的命令是Flush tables with read lock; (FTWRL)
6.2 表级锁
给当前操作的这张表加锁, MyISAM 与 InnoDB 引擎都支持表级锁定
加表锁:lock table read/write
解除表锁:
①show processlist
②kill 掉锁表的进程
6.3 页级锁
页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。因此,采取了折衷的页级锁,一次锁定相邻的一组记录。
6.4 行级锁
行级锁是 MySQL 粒度最小的锁,发生锁冲突概率最低,但是加锁慢,开销大
MySQL 中只有 InnoDB 引擎支持行锁,其他不支持。
MySQL 在执行 update、delete 语句时会自动加上行锁。
7.快照读和当前读
7.1快照读
快照读就是读取的是快照数据,不加锁的简单 Select 都属于快照读。
SELECT * FROM STUDENT WHERE ...
7.2当前读
当前读就是读的是最新数据,而不是历史的数据。加锁的 SELECT,或者对数据进行增删改都会进行当前读。
三、三大范式
1.第一范式
要求任何一张表都有主键,并且每一个字段原子性不可再分。
不满足第一范式可能会造成的问题:①数据冗余②更新异常③插入异常④删除异常
例:
建立一个描述学校教务的数据库,该数据库涉及的对象包括学生的学号(Sno)、所在系(Sdept)、系主任姓名(Mname)、课程号(Cno)和成绩(Grade)。假设用一个单一的关系模式Student来表示,则该关系模式的属性为:U={Sno, Sdept, Mname, Cno, Grade}
得到一个函数依赖F,F={Sno—>Sdept, Sdept—>Mname, (Sno, Cno)—>Grade}
存在的问题:每一个系的系主任姓名、所属系的信息重复出现;某个系更换系主任后,必须修改与该系学生有关的每一个条记录;一个系刚成立,暂时没有学生,则无法把这个系以及系主任的信息存入数据库;某个系的学生全部毕业了,则在删除该系学生信息的同时,这个系及系主任的信息也删除了。
2.第二范式
建立在第一范式的基础上,要求所有非主键字段对主键是完全依赖,不存在部分依赖。
不满足第二范式可能造成的问题:①插入异常②删除异常③修改重复
例:
有关系模式S-L-C(Sno, Sdept, Sloc, Cno, Grade),分别是学生的学号(Sno)、所在系(Sdept)、学生的住处(Sloc)、课程号(Cno)、课程成绩(Grade),并且每个系的学生都住在同一个地方。S-L-C的主键是(Sno, Cno),则函数依赖有:
(Sno, Cno)—>Grade
Sno—>Sdept, (Sno, Cno)—>Sdept
Sno—>Sloc, (Sno, Cno)—>Sloc
Sdept—>Sloc(每个系的学生只住在一个地方)
可以看到非主键字段Sdept、Sloc并不完全依赖于主键,则S-L-C(Sno, Sdept, Sloc, Cno, Grade)不符合第二范式定义。
3.第三范式
建立在第二范式的基础上,要求所有非主键字段直接依赖主键,不存在传递依赖。