基本概念解释
事务的四大特性:
1)原子性
事务作为一个整体,要么全部执行,要么都不执行。
2)一致性
事务执行前后,数据的整体性不会被破坏。
比如A和B各有100元,A给了B10元,事务前后他们总钱数都是200元不变。
3)隔离性
多个事务并发执行时,事务之间互不干扰。
4)持久性
事务提交后,数据操作的结果会被永久保存。
构建测试环境
创建一个表,拥有序号、姓名、携带金额如下。
id | name | money |
---|---|---|
1 | Alex | 100 |
2 | Bob | 100 |
3 | Cindy | 100 |
RU(读未提交)
RU采取读不加锁原理。
事务读不加锁,不阻塞其他事务的读和写;
事务写阻塞其他事务写,但不阻塞其他事务读。
事务顺序号 | 事务A | 事务B |
---|---|---|
1 | begin | |
2 | 读取Alex的金额是100 | |
3 | begin | |
4 | 修改Alex的金额为90 | |
5 | 读取Alex的金额为90 |
事务B没有提交,事务A却读取到了同一行内容,不同的数据。 出现脏读
。
RC(读已提交)
事务顺序号 | 事务A | 事务B |
---|---|---|
1 | begin | |
2 | 读取Alex的金额是100 | |
3 | begin | |
4 | 修改Alex的金额为90 | |
5 | commit | |
6 | 读取Alex的金额为90 | |
7 | commit |
事务A在进行的过程中,有一段完整的事务B,事务B对同一行内容的修改,使得事务A两次读取了不同的内容。读取同一条数据,却返回不同的内容。
出现不可重复读
。
RR(可重复读)
事务顺序号 | 事务A | 事务B |
---|---|---|
1 | begin | |
2 | 读取id大于等于2的金额,即Bob和Cindy的100 | |
3 | begin | |
4 | 插入一行id等于4,name是David,金额90 | |
5 | commit | |
6 | 再次查询id大于等于2,得到3行数据 |
在事务A执行过程中,有新的添加或删除数据的事务B,使得事务A两次查询结果不同。
出现幻读
。
Serializable(串行化)
强制事务串行执行。
读操作和写操作都不允许并发执行。
不同隔离级别遇到的问题
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | √ | √ | √ |
读已提交 | × | √ | √ |
可重复读 | × | × | √ |
串行化 | × | × | × |
MVCC实现原理
通过 Read View 和 Undo Log实现。Undo Log保存历史快照,Read VieW 判断数据是否可见。
Read View 是执行SQL语句时产生的读视图,来判断当前事务可见哪个版本的数据。
Undo Log 是回滚日志,记录数据被修改前的信息,数据在修改前会被拷贝到 Undo Log 中。当 delete 一条数据时,会在 Undo LOg 中增加一条对应的 insert 记录。 (记录相反的操作信息)
Undo Log 在事务回滚时,保持其原子性和一致性,并用于MVCC快照读。
1)获取事务ID
2)获取Read View
3)查询得到的数据,然后对事务版本号进行比较。
4)如果不符合Read View的可见性规则, 即就需要Undo log中历史快照;
5)最后返回符合规则的数据