MySQL事务之不可重复读问题

版权声明:本文为 小异常 原创文章,非商用自由转载-保持署名-注明出处,谢谢!
本文网址:https://blog.csdn.net/sun8112133/article/details/89739475








在事务的并发操作中,也就是多个事务同时对同一组数据进行操作时,可能会出现脏读、不可重复读、幻读、丢失更新这四个问题,本篇博客就来为大家讲解 不可重复读 问题。

一、不可重复读概述

不可重复读 就是一个事务读到另一个事务修改后并提交的数据(update)。在同一个事务中,对于同一组数据读取到的结果不一致。比如,事务B 在 事务A 提交前读到的结果,和在 事务A 提交后读到的结果可能不同。不可重复读出现的原因就是由于事务并发修改记录而导致的。
 
隔离级别 有四种,分别是:读未提交、读已提交、可重复读、序列化。
  读未提交: Read Uncommitted,顾名思义,就是一个事务可以读取另一个未提交事务的数据。最低级别,它存在4个常见问题(脏读、不可重复读、幻读、丢失更新)。
  读已提交: Read Committed,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。 它解决了脏读问题,存在3个常见问题(不可重复读、幻读、丢失更新)。
  可重复读: Repeatable Read,就是在开始读取数据(事务开启)时,不再允许修改操作 。它解决了脏读和不可重复读,还存在2个常见问题(幻读、丢失更新)。
  序列化: Serializable,序列化,或串行化。就是将每个事务按一定的顺序去执行,它将隔离问题全部解决,但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
 
大多数数据库默认的事务隔离级别是 Read Committed,比如 SQL Server , Oracle。但 MySQL 的默认隔离级别是 Repeatable Read。

1、事例

程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他买单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务并提交完)。程序员就会很郁闷,明明卡里是有钱的…

2、分析

在这个事例中,涉及到了两个事务(程序员事务和妻子事务),当程序员事务开启时,收费系统读取程序员卡里钱的操作还没完成,此时妻子这个事务就将卡里的钱进行了转账,即对数据进行了修改,导致收费系统两次读取到的数据不一样。出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读,这是由于数据更新导致的,不能重复读取相同的数据。

事务的不可重复读


二、演示不可重复读

1、新建一个数据库(bank库),并准备一张表(account表)

1、数据库和数据表

2、打开两个窗口,并分别设置自动提交方式为off

show variables like 'autocommit';   – 查看当前的自动提交是否开启

set autocommit = off;   – 将自动提交关闭

2、取消自动提交(A窗口)
2、取消自动提交(B窗口)

3、将A窗口的隔离级别设置成 “读已提交”

select @@tx_isolation;   – 查询当前的隔离级别

set session transaction isolation level read committed;   – 设置当前会话隔离级别为“读已提交”

3、设置隔离级别

4、两个窗口分别开启事务

start transaction;   – 开启事务 或 begin; 也可以显式开启事务

4、开启事务

5、在B窗口更改数据,并提交事务

use bank   – 切换到bank数据库

update account set money = money - 100 where id = 1;   – 修改account表中id为1的money字段数据

commit;   – 提交事务

5、更改数据

6、分别在数据库和A窗口中查看数据

select * from account;   – 查看account中的全部数据

6、查看数据(数据库)
6、查看数据(A窗口)

大家会发现数据库和A窗口中的数据都发生了改变,因为B窗口已经提交了事务,所以数据库中的数据发生改变,是属于正常现象。但是这种事务的隔离性似乎不是太好(事务的隔离性是一个事务的执行,不受其他事务的干扰),你看,B窗口提交了事务,影响到了A窗口中数据,这种隔离级别虽然解决了 ”脏读“ 问题,但是还会引发 “不可重复读”、“幻读”及“丢失更新” 问题,有关 “幻读”及“丢失更新” 的问题请参考后续博客。


有关事务的知识可以参考我之前写的博客《【Spring4.0笔记整理十七】Spring事务详解》【Spring4.0笔记整理十八】Spring事务管理详解


博客中若有不恰当的地方,请您一定要告诉我。前路崎岖,望我们可以互相帮助,并肩前行!



  • 18
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
MySQL不可重复读和幻读是在不同的事务隔离级别下出现的问题不可重复读是指在同一个事务中,多次读取同一行数据时,前后读取的结果不一致。而幻读则是指在同一个事务中,多次执行相同的查询语句时,返回的结果集不一致,可能会出现新增或删除的数据。 在MySQL中,不可重复读和幻读的出现与事务隔离级别有关。MySQL有四个事务隔离级别,分别是读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)和序列化(SERIALIZABLE)。 在读未提交的隔离级别下,会出现不可重复读和幻读的问题。因为读未提交允许一个事务可以读取到另一个未提交事务中的数据,这就可能导致读取到的数据在事务中发生了变化。 在读已提交的隔离级别下,不会出现不可重复读问题,因为该级别只允许读取到已经提交的数据。但是在读已提交的隔离级别下,仍然会出现幻读的问题。因为幻读是指某个事务在执行相同的查询语句时,由于其他事务的新增或删除操作,导致返回的结果集发生了变化。 可重复读是MySQL的默认事务隔离级别,它解决了不可重复读问题。在可重复读的隔离级别下,事务执行期间,读取的数据集会保持一致,不会受到其他事务的修改影响。但是可重复读隔离级别下仍然会出现幻读的问题,因为幻读是由于其他事务的插入操作导致的。 为了解决幻读的问题,可以使用序列化的隔离级别。在序列化的隔离级别下,MySQL会对所有并发的事务进行串行化执行,确保每个事务之间是完全隔离的,不会出现不可重复读和幻读的问题。 综上所述,MySQL不可重复读和幻读问题是与事务隔离级别相关的。在读未提交的隔离级别下,会出现不可重复读和幻读问题;在读已提交的隔离级别下,不会出现不可重复读问题但仍然会出现幻读问题;在可重复读的隔离级别下,解决了不可重复读问题但仍然会出现幻读问题;而使用序列化的隔离级别可以解决不可重复读和幻读的问题
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小异常

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值