MySQL可重复读级别会不会造成幻读

一、定义

在《高性能MySQL》一书中,是这样描述的
在这里插入图片描述
根据书上的描述,MySQL的可重复读隔离级别通过MVCC机制,解决了幻读的问题,所以不会造成幻读

二、测试

本文默认你已经知道以下的命令

1. 查询当前会话隔离级别

SELECT @@tx_isolation;

2. 设置当前会话隔离级别

set SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

3. 查询正在进行中的事务

SELECT * FROM information_schema.INNODB_TRX

准备实验的表和数据

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) DEFAULT NULL,
  `age` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`id`)
);
INSERT INTO user VALUES (1, '张三', 1);

测试表数据如下:
在这里插入图片描述
打开两个会话窗口,分别都设置隔离级别为RR

按照顺序执行以下操作

事务A事务B
START TRANSACTION
SELECT * FROM user
START TRANSACTION
INSERT INTO user values(2,'李四',1)
commit
SELECT * FROM user
update user set age = 2
SELECT * FROM user

按照上图序号标注的顺序,从①到⑥,在⑥查询的时候,发现确实是没有查到B事务新增的数据的,所以确实没有幻读。但是再执行⑦、⑧,会发现在⑧的时候,出现了幻读

三、分析

这里默认你已经知道了MVCC的原理,可以参考这篇文章MYSQL MVCC实现原理

简单来说,就是MySQL会默认给表增加两个字段,一个是标记创建时间,一个标记过期时间(也是删除时间),这里的时间指的是当前事务的id

SELECT
InnoDB会根据以下两个条件检查每行记录:

  • InnoDB只查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
  • 行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未被删除。

只有符合上述两个条件的记录,才能返回作为查询结果

INSERT
InnoDB为新插入的每一行保存当前系统版本号作为行版本号。

DELETE
InnoDB为删除的每一行保存当前系统版本号作为行删除标识。

UPDATE
InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。

带上这两个字段,分析下测试数据

执行完②

idnameage创建时间删除时间
1张三11

执行完⑤

idnameage创建时间删除时间
1张三11
2李四12

执行⑥的时候,根据SELECT的时候版本号规则,查询小于等于当前版本号,所以只能查出id = 1的数据,没有幻读

执行完⑦

idnameage创建时间删除时间
1张三11
2李四121
2李四11

根据UPDATE的版本号规则,现在数据库应该有三条数据

所以再执行⑧的查询,根据SELECT的查询规则,应该是能看到新增的数据,产生了幻读

四、总结

所以我认为MySQL的MVCC机制并没有完全解决幻读问题。

这是我自己的理解,如果有误还请指出

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值