目录:
- 什么是事务
-
- ACID 特性
- 2.1. 原子性(Atomicity)
- 2.2. 一致性 (Consistency)
- 2.3. 隔离性(Isolation)
- 2.4. 持久性(Durability)
-
- 并发的问题
- 3.1. 更新丢失
- 3.2. 脏读
- 3.3. 不可重复读
- 3.4. 幻读
-
- 隔离级别
- 4.1. 读未提交(Read Uncommitted)
- 4.2. 读已提交(Read Committed)
- 4.3. 可重复读(Repeatable Read)
- 4.4. 串行化(Serializable)
- 总结
对 MySQL 的重新学习,不用复杂的表达,简单通俗的方式复习知识、巩固基础
1. 什么是事务
一系列数据库操作的集合,主要就是 CURD
一个有规矩的团体,一起行走
- 同生共死,原子性
- 佛系处事,一致性
- 互不影响,隔离性
- 信守诺言,持久性
2. ACID 特性
2.1. 原子性(Atomicity)
事务像原子一样不可分割
要么全部成功,不会出现只有部分操作成功
要么全部失败,进行回滚,回到最初的状态,好像什么也没发生过
操作们要同生共死
事务:小白给小黑转账
- 在一个事务期间,先转 100,再转 100
- 成功提交后就转 200,不会出现只有部分转账成功
- 失败回滚后一分钱也没转
2.2. 一致性 (Consistency)
事务使数据库从一个一致性的状态转换到另一个一致性的状态
有点像物理学的质量守恒和能量守恒
佛系处事,云卷云舒,花开花落,大千世界不会因为我而改变
事务:小白和小黑转账
- 事务开始前,小白和小黑还是一共有 200 元
- 事务执行期间,两者互相转账多次,数额不定
- 事务完成后,小白和小黑还是一共有 200 元
2.3. 隔离性(Isolation)
多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰
多个并发事务之间要相互隔离
并发发生后,事务是可以同时访问同一行数据的
事务又是孤僻的,我过我的独木桥,你走你的阳关道
三个人转账:
- 事务1:小白给小黑转账 100
- 事务2:期间小黑给小红转账 100
- 这两个事务要互不影响,不会出现错乱
2.4. 持久性(Durability)
事务一旦移交,对数据的改变是永久性的
发生故障不应该有任何影响
做了什么就是什么,已经刻入我的人生,无法逆转
事务:小白给小黑转账
- 成功转账 100
- 服务器崩溃又重启
- 这个结果不会改变
3. 并发的问题
事务应该是互不来往,大家各走各路
现实情况是总有资源是交错的
比如两个事务一起执行时,同时又有对同一行数据由读写操作
难以避免的冲突发生了
会有四种形式出现
3.1. 更新丢失
一个事务把另一个事务的更新覆盖
小白和小黑给小红转账
- 小红的帐户初始为 0
- 事务1:小白先转 100,小红的账户为 100,但还未提交
- 事务2:小黑也转 100,因为小白没提交,不知道小白的转账,小红的账户也为 100
- 两个事务提交,小红结果只有 100
- 有 100 被蒸发了,可怕!
3.2. 脏读
一个事务读取了另一个事务未提交的数据
数据还没提交,允许其他事务读取
未提交的事务回滚会发生异常
小白和小黑给小红转账
- 小红初始账户为 0
- 事务1:小白先转 100,小红的账户为 100,还未提交
- 事务2:小黑读到小白的转账,也转了 100,小红的账户为 200
- 小白没有提交,不转了,事务1回滚;小黑提交了转账,事务2提交
- 小红的账户应该为 100 的,多出了 100,可怕!
3.3. 不可重复读
一个事务读取表中某一行数据,多次读取的结果不同
因为在读的时候,还允许其他事务修改数据
小红在查自己账户,小白的转账
- 小红的初始账户为 0
- 事务1:小红查账,有两次查询
- 事务2:小白给小红转账 100
- 事务1 第一次查询,小红读到 0
- 期间事务 2 执行成功
- 事务2 第二次查询,小红读到 100
- 有点迷,小红的账户应该是哪个值
如果以最后读到的数据为准,也有个隐患,也就是事务1发生回滚,那么这个数据也是错的
3.4. 幻读
一个事务读取了别的事务插入的数据,导致前后读取不一致
发生在事务读取一个指定范围内的数据
事务读取的期间,刚好有其他事务进行插入数据的操作,而且这个操作的值刚好就发生在这个指定范围内
那么就像幻觉一样,见鬼了,两次读取的数据不一致
小黄在查金额为 100 的账户
- 小白的初始账户为 0,小黑的初始账户为 100
- 事务1:小黄有两次查询
- 事务2:小红向小白转账 100
- 事务1 开始,小黄第一次查询,满足要求的是小黑
- 这个时候事务2 开始,小白的账户也为 100
- 事务2 开始,小黄第二次查询,满足要求的居然出现了小白
- 有点迷,小黄不知道哪个是准确的
4. 隔离级别
针对事务并发出现的几种问题,衍生出 4 种程度不一的隔离级别
对一行数据的操作,总体上可以认为是两种
- 修改操作
- 读取操作
既然对同一行的数据的读写,会发生争端,那么就来立几个规矩
- 更新丢失的问题,有事务修改,就不允许其他事务也进行修改,很好地解决
- 然后具体主要讨论读数据的问题
4.1. 读未提交(Read Uncommitted)
一个事务对一行数据的修改过程中
- 允许其他事务读取
- 禁止其他事务进行修改
最低级别的隔离
只解决了更新丢失的问题,脏读、不可重复读、幻读均会发生
4.2. 读已提交(Read Committed)
一个事务对一行数据的操作:
- 修改操作,禁止其他一切事务访问该行
- 读取操作,允许其他事务访问该数据
因为修改操作,其他事务无法访问,就没有了读取未提交数据产生脏数据的情况发生
但是读取操作,其他事务可能会修改该行,所以会发生不可重复读问题,比如几次读取数据都不一样
幻读和插入新数据有关,也没有解决
4.3. 可重复读(Repeatable Read)
一个事务对一行数据的操作:
- 修改事务,禁止其他一切事务访问该行
- 读取操作,禁止其他事务修改,允许其他事务读取
可以看到在读已提交的隔离级别上又进了一步,
修改数据和读已提交是一样的,所以不会有脏数据
读取操作,禁止其他事务进行修改,也就不会出现多次读取不一样的数据,不可重复读解决了
perfect!
但是插入新行呢,幻读还是有的
幻读问题和读写一行数据无关,和插入新数据有关,所以一些存储引擎采取了其他方式来避免幻读问题
比如 InnoDB 和 Falcon 存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决该问题
4.4. 串行化(Serializable)
所有事务串行执行
因为没有了对同一行数据的同时操作
所以脏读、不可重复读不会发生
又连插入数据的事务也跟着排队,幻读同样不会发生
效率太低了
5. 总结
这四种隔离级别可以用一张表格来表示:
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
未提交读(Read uncommitted) | √ | √ | √ |
已提交读(Read committed) | × | √ | √ |
可重复读(Repeatable read) | × | × | √ |
可串行化(Serializable) | × | × | × |
大部分数据库使用 Read Committed 的隔离级别
MySQL 默认使用 Repectable Read 隔离级别
![](https://img.haomeiwen.com/i460263/82b31ef3505a9684.jpeg)
网友评论