原来事务隔离级别可以这样理解

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 隔离级别

在这里插入图片描述

发布了61 篇原创文章 · 获赞 43 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/firefile/article/details/86708127