快速理解 脏读、不可重复读、幻读(解决方法)

事务在并发执行时遇到的问题

我们需要舍弃一部分的隔离性来换取数据库的并发的性能,怎么个舍弃法呢?先得看一下访问相同数据的事务在不保证串行执行(也就是执行完一个再执行另一个)的情况下可能会出现哪些问题:

脏读【读取数据未提交】

一个事务读取另外一个事务未提交的更新事务。

事务1事务2
select age from table1 where id = 1 – 结果是 20
update table1 set age = 30 where id = 1 – 这里没有提交
select age from table1 where id = 1 – 结果是 30
事务2回滚
备注正常事务1 的结果应该是20

这里的事务1就读取了一条脏数据。 – 脏读

不可重复读【前后多次读取,数据内容不一致】

在一个事务范围内, 同样的两次查询得到不同的结果。这里是由于系统中其他的事务提交引起的。

事务1事务2
select age from table1 where id = 1 – 结果是 20
update table1 set age = 30 where id = 1 – 这里提交了
select age from table1 where id = 1 – 结果是 30
备注按照正确逻辑,事务A前后两次读取到的数据应该一致

幻读【前后多次读取,数据总量不一致】

幻读是不可重复读的一种特殊情况, 在同一个事务范围内, 查询两次结果得到条数不一样。

事务1事务2
select count(*) from table1 结果是 20
insert into table1 value(9,…) – 这里提交了
select count(*) from table1 – 结果是 21
备注按照正确逻辑,事务A前后两次读取到的数据总量应该一致

数据库事务隔离级别

事务的隔离性指的是什么:并发执行的时候,事务是相互隔离的,一个事务的执行不能被其他的事务干扰。

什么是数据库隔离级别

  • 我们知道MySQL是一个客户端/服务器架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就可以称之为一个会话(Session)。
  • 每个客户端都可以在自己的会话中向服务器发出请求语句,一个请求语句可能是某个事务的一部分,也就是对于服务器来说可能同时处理多个事务。
  • 在事务简介的章节中我们说过事务有一个称之为隔离性的特性,理论上在某个事务对某个数据进行访问时,其他事务应该进行排队,当该事务提交之后,其他事务才可以继续访问这个数据。但是这样子的话对性能影响太大,我们既想保持事务的隔离性,又想让服务器在处理访问同一数据的多个事务时性能尽量高些,鱼和熊掌不可得兼,舍一部分隔离性而取性能者也。

在这里插入图片描述
我们上边所说的舍弃一部分隔离性来换取一部分性能在这里就体现在:设立一些隔离级别,隔离级别越低,越严重的问题就越可能发生。有一帮人(并不是设计MySQL的大叔们)制定了一个所谓的SQL标准,在标准中设立了4个隔离级别

  • READ UNCOMMITTED:未提交读。

  • READ COMMITTED:已提交读。

  • REPEATABLE READ:可重复读。

  • SERIALIZABLE:可串行化。

一图胜千言
事务C 和 AB 是并行的

未提交读

一个事务可以读取另外一个事务未提交的事务。
1.事务在读数据时候没有加锁。
2.在修改数据的时候只是对事务增加行级共享锁。产生现象:

事务1在读取的时候, 事务2也可以进行读取以及修改。(事务在读取的时候是不加锁的)
事务2在这条记录进行修改时候, 事务1可以进行读取。(因为事务在修改的时候只是加了共享锁),
所以,这样就会产生脏读。

当隔离级别设置为Read uncommitted 时,就可能出现脏读,如何避免脏读,请看下一个隔离级别。

读已提交 Read Committed

读已提交是PostgreSQL里的缺省隔离级别。
当一个事务运行在这个隔离级别时, SELECT查询(没有FOR UPDATE/SHARE子句)只能看到其它事务已提交的数据。
实际上,SELECT 查询看到一个在查询开始运行的瞬间该数据库的一个快照。 不过,SELECT看得见其自身所在事务中之前的更新的执行结果,即使它们尚未提交。
请注意, 在同一个事务里两个相邻的SELECT命令可能看到不同的快照,因为其它事务会坑你在两个SELECT执行期间提交。
不会出现可脏读,但是不可重复读

可重复读 Repeatable Read

即使数据被其他事物修改, 当前事务也不会读取到新的数据
重复读事务中的查询看到的是事务开始时的快照, 而不是该事务内部当前查询开始时的快照,这样, 同一个事务内部后面的SELECT命令总是看到同样的数据,
也就是说,它们看不到 它们自身事务开始之后提交的其他事务所做出的改变。
不会出现可脏读, 可重复读, 可以幻读

可串行化 Serializable

可串行化级别提供最严格的事务隔离。这个级别为所有已提交事务模拟串行的事务执行, 就好像事务将被一个接着一个那样串行(而不是并行)的执行。
不过,正如可重复读隔离级别一样, 使用这个级别的应用必须准备在串行化失败的时候重新启动事务。
事实上,该隔离级别和可重复读希望的完全一样, 它只是监视这些条件,以所有事务的可能的序列不一致的(一次一个)的方式执行并行的可串行化事务执行的行为。
这种监测不引入任何阻止可重复读出现的行为,但有一些开销的监测,检测条件这可能会导致串行化异常 将触发串行化失败。

锁就是防止其他事务访问指定的资源的手段。锁是实现并发控制的主要方法,是多个用户能够同时操纵同一个数据库中的数据而不发生数据不一致现象的重要保障。 一般来说,锁可以防止脏读、不可重复读和幻觉读。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值