可重复读如何解决幻读

学习之前的疑问:
可重复读的概念 与 不可重复读的概念
行锁+gap锁(间隙锁)
快照读 与 当前读区别
快照读中的MVCC
当前读中的gap锁 和 行锁

前几天面试时被问到了mysql可重复读如何解决幻读的问题,之前脑子中的概念只有增加了共享锁和排他锁进行避免,没有实践或者清晰的概念,今天首先实践验证和理解mysql下可重复读对于幻读的避免和原理。参考博文:https://blog.csdn.net/Y0Q2T57s/article/details/103708206

首先整体了解数据库的隔离级别:

读未提交 -------------- 可能产生脏读,幻读,不可重复读
读已提交(不可重复读)----------------- 可能产生不可重复读,幻读
可重复读 ---------------------------------可能产生幻读
序列化 -----------------------------------无

可重复度和不可重复读

  • 概念:
  1. 不可重复读指的是事务1和事务2同时获取数据,在此时事务2进行插入行或者修改行操作,这时事务1再次进行select时会发现多了几行数据或者数据不一致,这就称为幻读
  2. 可重复读,也就是在RR隔离级别下,为了避免不可重复读的幻读情况发生,事务2修改数据的结果 在事务1是无法获取的,进行了隔离,这个实现后面会介绍到MVCC。

在了解了mysql的几个隔离级别后,针对可重复读是如何防止产生幻读的?

  • 先来通过实践验证简单的:如何防止如不可重复读的情况
    首先创建一张表
Create Table: CREATE TABLE `dept` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8

开启两个事务
在这里插入图片描述
表中没有数据,现在我们往右边事务中插入一条数据,如果在不可重复的隔离级别下在左边事务再select会发现新插入数据,而可重复读的情况下左边的select数据一直不变。
在这里插入图片描述

  • 解释:这一现象的原理是RR即可重复读的隔离级别下用到了MVCC,多版本并发控制,每个事务在开启时会有一个版本号,不管其他事务如何数据,而当前事务中的版本号不会变化,所以左边事务一直select的数据都是一个版本中的,所以不会读取到右边事务插入后的数据。
在左边事务中发现内容为空,我们插入一个id=29的数据行,看看会发生什么

在这里插入图片描述

  • 解释:这是什么情况呢?这是因为在select时会使用到快照读,但是在例如上面insert时会进行当前读, 如字面意思解释,快照读即事务开启时产生的版本号一般,进行了数据表当前的数据“复制”,在事务中select时只会用到快照读,但是如果进行insert/ update / select … for update 这种语句时,会进行当前读,访问数据表中“最新”的数据,这时尽管右边的insert未提交,但当前读还是会读到, 那么根据报错的信息,lock,得知在右边事务insert一行之后会进行加锁 (X锁),不允许其他事务修改,但能读取当前数据(当前读)即获取当前行的S锁,左边insert需要在右边事务释放锁之后才能进行insert/update操作(commit或者rollback)

下面对X锁和S锁进行学习

  • X锁称为排他锁(悲观锁) ----- 对目标行添加当前事务的X锁,即可修改或删除操作
  • S锁称为共享锁(共享锁) ----- 对目标行添加当前事务的S锁,即可读当前行的数据
    S锁是可以兼容的,即多个事务都可以持有对某行的读权限, 而X锁是不兼容的,即最多只有一个事务能获取当前行的修改或删除权限, 若其他事务需要获取X锁,必须等当前拥有X锁权限的事务释放X锁才能获取。

而上面出现的情况是因为 右边事务在Insert时便对id=29的行数据添加了X锁,而这时左边事务要对id=29的行进行X操作,那么首先需要获取已经被右边事务拥有的X锁,那么需要等右边事务释放X锁权限(commit或者rollback)才能获取.

  • 还有如下情况: 在这里插入图片描述
    如上面解释,如果右边事务插入id=99的数据行,如果左边事务修改id范围不包含99的话应该可以操作,但是左边事务也遇到了锁,导致不能修改成功,这是因为上面的X锁不仅包含了当前一行,还有(-无穷大, 10) 和 (10,+无穷大)加锁, 在左边事务update时,会遇到间隙锁(GAP锁),导致需要等待右边事务释放锁后才能更新。
通过上面可重复读中几种情况,总结:可重复读本身还是存在幻读的,但是因为在可重复读上添加了NEXE-KEY锁(即行锁+gap锁)避免了幻读的产生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值