【MySQL理论】脏读、不可重复读、幻读

1. 脏读(dirty read)

脏读是指事务读取到其他事务未提交的数据

例如:有事务A、B和一条记录:id为1,name为张三

B首先进行更新操作,将name的值由张三改为张老三,但还未提交事务

begin;
update stu set name = '张老三' where id = 1

然后A进行查询操作,查询姓名为张老三

select name from stu where id = 1

然后B由于某种原因被回滚,name自然从张老三恢复到了张三

A就会出现一个问题,读取的是张老三,但数据库中实际存储的是张三,我到底是用哪一个呢?

这就是脏读,事务A读取到事务B未提交的数据

脏读是我们在整个数据库操作中最普遍的一个现象,但是在日常开发中我们几乎不会遇到脏读,原因后面说

看图更容易理解
在这里插入图片描述

2. 不可重复读(non-repeatable read)

不可重复读是指在同一次事务中前后查询不一致的问题

例如:

A先查询了一条记录,name为张三

select name from stu where id = 1

然后B执行了更新,并且提交

begin;
update stu set name = '张老三' where id = 1;
commit

A再次按相同条件查询该记录,name为张老三

select name from stu where id = 1

A就会出现一个问题,同样的查询语句,两次的执行结果却不一致(不重复)

第二次查询得到的name应该还是预期的张三,因为很明确,A并没有对name进行修改,但是在并发环境下,假如两条select语句间有另外一个事务对name执行了update操作并提交了,把张三的名字改为了张老三,A再次执行同样查询导致name由张三变为张老三

A就有意见了,我明明没有对name进行修改,可是为什么后来变成张老三了?谁改我数据了?

这就是不可重复读:同一次事务中前后查询不一致

它会让我们的程序运行变得不可预期、不可控

看图更容易理解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tJ2rTdRb-1631029938002)(C:\Users\PC\AppData\Roaming\Typora\typora-user-images\image-20210907231354003.png)]

3. 幻读(phantom read)

幻读是一次事务中前后数据量发生变化,用户产生不可预料的问题

分为并发删除和并发插入的情况

1 并发插入

A先执行查询,假设当前只有一条数据,查询结果:id=1,name=张三

select * from stu

B插入了一条数据(已设置主键自增,省略id字段),name为李四

insert into stu(name) values('李四')

当A再次按相同条件查询

select * from stu

结果多了一条李四的记录(id=2,name=李四),刚才明明只有一条记录,怎么多出来一条?好像出现了幻觉

2 并发删除

将上面的插入操作换成删除操作,B删除了张三的记录

delete from stu where id = 1

结果A会发现张三的记录神秘的消失了,明明刚才还有的,怎么又没了,再次出现了幻觉

这就是幻读,看图更容易理解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ma99aVHO-1631029938005)(C:\Users\PC\AppData\Roaming\Typora\typora-user-images\image-20210907234039087.png)]

4. 不可重复读和幻读的比较

1 幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
2 不可重复读的重点是修改,幻读的重点在于插入或者删除
3 但如果从控制的角度来看, 两者的区别就比较大
对于前者, 只需要锁住满足条件的记录
对于后者, 要锁住满足条件及其相近的记录

5. 总结

脏读是指事务读取到其他事务正在处理的未提交数据

不可重复读指在并发更新时,另一个事务前后执行相同条件的查询得到的数据不一致

幻读指并发插入、删除时,另一个事务前后执行相同条件的查询得到的数据不一致

6. 解决方法

如何解决以上问题,事务的隔离级别就派上用场了

禁止写时读,避免了“脏读”,对应隔离级别read committed。

禁止读时写,避免了“不可重复读”,对应隔离级别repeatable read。

而为了避免“幻读”,干脆把整个表给锁住了,只能是serialize了。

隔离级别越高,并行度越低,付出的代价越大。

MySQL默认事务隔离级别为:可重复读(repeatable-read),因此当我们使用MySQL进行实际开发时一般不会发生“脏读”和“不可重复读”。现在可能遇到的问题就是“幻读”,不过MySQL通过多版本并发控制(MVCC)机制解决了该问题。

  • 22
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
脏读是指一个事务可以读取到另一个事务未提交的数据。不可重复读是指在一个事务内多次读取同一数据时,由于其他事务的修改导致每次读取的结果不一致。幻读是指在一个事务内多次执行相同的查询,由于其他事务的插入或删除导致每次查询的结果不一致。 在MySQL中,事务隔离级别对应的脏读不可重复读幻读的情况如下: - 读未提交(READ UNCOMMITTED)级别下存在脏读不可重复读幻读的问题。 - 读已提交(READ COMMITTED)级别下不存在脏读的问题,但仍可能存在不可重复读幻读的问题。 - 可重复读(REPEATABLE READ)级别下不存在脏读不可重复读的问题,但仍可能存在幻读的问题。 - 串行化(SERIALIZABLE)级别下不存在脏读不可重复读幻读的问题。 因此,在MySQL中,脏读不可重复读幻读都是与事务隔离级别密切相关的读一致性问题。根据需求和业务场景,可以选择合适的事务隔离级别来解决这些问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Mysql-详解脏读不可重复读幻读](https://blog.csdn.net/ahuangqingfeng/article/details/124407846)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [一文搞懂MySQL脏读,幻读不可重复读](https://blog.csdn.net/liuqinhou/article/details/126360614)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值