目录

  • 前言
  • 并发事务产生的问题
    • 更新丢失
      • 回滚丢失
      • 覆盖丢失
    • 脏读
    • 不可重复读
    • 幻读
  • 快照读和当前读
  • 幻读验证
    • 快照读如何避免幻读
    • 当前读如何避免幻读
    • 可重复读隔离级别发生幻读情况
  • 小结

前言

Mysql在可重复读(REPEATABLE READ)隔离级别下,如何解决部分幻读问题?本文将对这个问题进行探究。

并发事务产生的问题

先创建一张用户表,用作数据验证:

CREATE TABLE `user` (`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',`name` varchar(20) DEFAULT NULL COMMENT '姓名',PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';

事务并发处理可能会带来一些问题,比如:更新丢失、脏读、不可重复读、幻读等。

  • 更新丢失:

当两个或多个事务更新同一行记录,会产生更新丢失现象。可以分为回滚覆盖和提交覆盖。

回滚覆盖:一个事务回滚操作,把其他事务已提交的数据给覆盖了。
提交覆盖:一个事务提交操作,把其他事务已提交的数据给覆盖了。

  • 脏读: 一个事务读取到了另一个事务修改但未提交的数据。
  • 不可重复读: 一个事务中多次读取同一行记录不一致,后面读取的跟前面读取的不一致。
  • 幻读: 一个事务中多次按相同条件查询,结果不一致。后续查询的结果和面前查询结果不同,多了或少了几行记录。

更新丢失

回滚丢失

一个事务回滚操作,把其他事务已提交的数据给覆盖了。

开启事物A

开启事物B

查询id = 1的数据name= 张三

更新id为1的数据保存name= 李四

更新id为1的数据保存name= 王二

提交事物

回滚事物

name恢复张三,更新丢失

在MySQL数据库,任何隔离级别不会出现第一类更新丢失

覆盖丢失

一个事务提交操作,把其他事务已提交的数据给覆盖了。

开启事物A

开启事物B

查询id = 1的数据name= 张三

更新id为1的数据保存name= 李四

更新id为1的数据保存name= 王二

提交事物

提交事物

name被修改为王二,更新丢失

脏读

一个事务读到其他事务未提交的数据。

事物A 事物B
begin;
begin;
第一次查询:select name from user where id =1;结果:张三
update user set name=‘李四’ where id = 1;
第二次查询:select name from user where id =1;结果:李四
comit;

不可重复读

一个事务读取到其他事务修改过的数据。

事物A 事物B
begin;
begin;
第一次查询:select name from user where id =1;结果:张三
update user set name=‘李四’ where id = 1;
comit;
第二次查询:select name from user where id =1;结果:李四

从上面的示例中,可以看出,在事务B修改完数据,并提交事务后。事务A第二次查询已经读到事务B最新修改的数据,这种情况就属于不可重复读。

幻读

一个事务读取到其他事务最新插入的数据。

事物A 事物B
begin;
begin;
第一次查询:select name from user where id >0;结果:张三
insert into user (name) values(‘李四’) ;
comit;
第二次查询:select name from user where id >0;结果:张三 李四

快照读和当前读

快照读: 读取数据的历史版本,不对数据加锁。

例如:

select

当前读: 读取数据的最新版本,并对数据进行加锁。

例如:

insert、update、delete、select for update、select lock in share mode

幻读验证

MySQL在Repeatable Read(可重复读)隔离级别下,有没有解决幻读的问题?

部分解决了幻读问题。

事务查询和设置:

#查询全局事务隔离级别
show global variables like '%isolation%';
SELECT @@global.tx_isolation;
#设置全局事务隔离级别
set global transaction isolation level REPEATABLE READ;
#设置完成后,只对之后新起的 session 才起作用,对已经启动 session 无效。#查询会话事务隔离级别
show session variables like '%isolation%';
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
#设置会话事务隔离级别
set session transaction isolation level REPEATABLE READ;

快照读如何避免幻读

事物A 事物B
begin;
begin;
第一次查询:select name from user where id >0;结果:张三
insert into user (name) values(‘李四’) ;
comit;
第二次查询:select name from user where id >0;结果:张三

可重复读隔离级是由 MVCC(多版本并发控制)实现的,从上面的示例中,可以看出,事务A的两次查询,得到的结果一致,并没有查到事务B最新插入的数据。原因是,第一次快照读的时候,生成了一个读视图(Read View)。后续的查询语句通过这个 Read View 就可以在 undo log 版本链找到事务开始时的数据,所以事务过程中每次查询的数据都是一样的,所以两次查询得到的结果一致。

undo log

undo log是InnoDB的事务日志。undo log是回滚日志,记录的是行数据的修改记录,即哪些行被修改成怎样,提供回滚操作。事务的操作记录会被记录到undo log中,用于事务进行回滚操作。

版本链
在InnoDB中,每个行记录都隐藏着两个字段:

1)trx_id:事务id。该字段用于记录修改当前行记录的事务的id。
2)roll_pointer:回滚指针。该字段用于记录修改当前行记录的undo log地址。

ReadView主要包括四个部分:

  1. m_ids:表示在生成ReadView时当前系统中活跃的读写事务的id。
  2. min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务的最小id。
  3. max_trx_id:表示在生成ReadView时系统应该分配给下一个事务的id值。
  4. creator_trx_id:表示生成该ReadView的事务的id。

读已提交在每次读数据前都会生成一个ReadView,这样可以保证每次都能读到其他事务已提交的数据。可重复读只在第一次读取数据时生成一个ReadView,这样就能保证后续读取的结果一致。

当前读如何避免幻读

#事物A
begin;
select * FROM user1 WHERE id > 0 for update;
SELECT SLEEP(20);
select * FROM user1 WHERE id > 0 for update;
#事物B
BEGIN;
insert into user1(name) VALUES ('三省同学');
commit;
事物A 事物B
begin;
begin;
第一次查询:select name from user where id >0 for update;结果:张三
insert into user (name) values(‘三省同学’) ;【被阻塞】
comit;
第二次查询:select name from user where id >1 for update;结果:张三

Innodb 引擎为了解决「可重复读」隔离级别使用「当前读」而造成的幻读问题,就引出了间隙锁。读提交隔离级别,是没有间隙锁的,只有记录锁。

next-key lock = 间隙锁+记录锁

可重复读隔离级别发生幻读情况

示例1:

事物A 事物B
begin;
begin;
第一次查询:select name from user where id >0;结果:张三
insert into user (name) values(‘三省同学’) ;
comit;
第二次查询:select name from user where id >1 for update;结果:张三 三省同学

第二次获取当前最新数据,整个事务也发生了幻读。

示例2:

事物A 事物B
begin;
第一次查询:select name from user where id >0;结果:张三
begin;
insert into user (id, name) values(2, ‘三省同学’) ;
comit;
update user set name = ‘三省同学’ WHERE id =2;
第二次查询:select name from user where id >1;结果:张三 三省同学

事务 A 第一次执行普通的 select 语句时生成了一个 ReadView,之后事务 B 向表中新插入了一条 id = 2的记录并提交。接着,事务 A 对 id =2这条记录进行了更新操作,在这个时刻,这条新记录的 trx_id 隐藏列的值就变成了事务 A 的事务 id,之后事务 A 再使用普通 select 语句去查询这条记录时就可以看到这条记录了,于是就发生了幻读。

小结

MySQL InnoDB 引擎的可重复读隔离级别(默认隔离级)下避免幻读:

快照读通过 MVCC 方式解决了幻读。
当前读通过 next-key lock解决了幻读。

点赞 收藏 关注
踔厉奋发,勇毅前行

Mysql在可重复读事务隔离级别下怎么解决幻读的相关推荐

  1. Mysql可重复读隔离级别下如何解决幻读

    Mysql可重复读隔离级别下如何解决幻读 一些概念 具体加锁说明 使用主键索引进行等值查询 使用主键索引进行范围查询 使用二级索引进行等值查询 使用二级索引进行范围查询 一些概念 幻读:在一次事务中, ...

  2. 深入学习InnoDB可重复读隔离级别下如何避免幻读

    一.InnoDB可重复读隔离级别下如何避免幻读 在理解什么是幻读之前,先了解下脏读.幻读.不可重复读在实操场景中的现象. 脏读:指的就是一个事务读取到了另一个事务还未提交的数据,当该事物将数据回滚,则 ...

  3. MySQL可重复读隔离级别为何没有解决幻读(MVCC原理简介)

    MySQL可重复读隔离级别为何没有解决幻读(MVCC原理简介) 一.MCVV简介 二.可重复读隔离级别能解决幻读? 三.什么是当前读和快照读? 四.MVCC的实现原理 五.RC,RR级别下的InnoD ...

  4. 浅析SQL Server在可序列化隔离级别下,防止幻读的范围锁的锁定问题

    本文出处:http://www.cnblogs.com/wy123/p/7501261.html  (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些 ...

  5. mysql 事务隔离规范_MySQL事务隔离级别以及脏读、幻读、不可重复读示例

    事务的隔离性 MySQL是一个客户端/服务器架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就可以称之为一个会话(Session).每个客户端都可以在自己的 ...

  6. MySQL事务隔离级别以及脏读、幻读、不可重复读示例

    事务的隔离性 MySQL是一个客户端/服务器架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就可以称之为一个会话(Session).每个客户端都可以在自己的 ...

  7. 脏读、幻读和不可重复读 + 事务隔离级别

    丢失更新:两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的: 1. 脏读 :脏读就是指当一个事务正在访问数据,并且对数据进 ...

  8. MySQL 事务默认隔离级别?能否解决幻读?

    事务隔离级别 MySQL 中事务隔离级别有 read uncommited.read commited.repeatable read.serializable 四种,其中默认为 repeatable ...

  9. Mysql RR级别下如何解决幻读

    快照读 在RR级别下,Mysql是根据MVCC来解决快照读时发生的幻读现象,简单来说就是利用了版本链以及Read View来实现的,RR下只有事务刚一开始时才会产生Read View,后续都会使用这个 ...

最新文章

  1. szu 寒训第二天 树状数组 二维树状数组详解,以及树状数组扩展应用【求逆序对,以及动态第k小数】
  2. 需要注意变量作用域的使用
  3. TestNG之注解的生命周期
  4. 1027 Colors in Mars (20 分)_20行代码AC
  5. 计算机网络名词解释-csma cda,计算机专业对口升学模拟题1资料.doc
  6. wget连接指定端口_新技能:wget参数有用过吗?
  7. java this() super()_java中的this和super
  8. php生成网页缩略图接口,php生成网站缩略图
  9. 网站集搜索中心的搜索页面对应路径:
  10. Spring框架配置文件 application.xml 示例
  11. mysql主从 副本集,MongoDB的主从、副本集模式
  12. 制作openstack系统镜像
  13. 如何制作PE系统盘?
  14. 5G+AI+大数据+IoT如何改变一切?
  15. matlab mosa算法,尔雅尔雅2020年科学计算与MATLAB语言答案大全
  16. CSS3(新增选择器,nth选择器,伪元素)
  17. 客户留存的4个产品策略
  18. 【报告分享】百度创新营销资源整合方案(2021)-百度营销研究院(附下载)
  19. java求幸运数字_Java 第几个幸运数
  20. 互联网10大最有效的盈利模式

热门文章

  1. MachineKey
  2. css背景颜色透明,字体不透明
  3. 华为基站服务器芯片,华为发布5G基站核心芯片“天罡”
  4. 低仿网易云音乐音频播放器!自动获取歌曲封面,并旋转
  5. 【删除数组中重复的元素】
  6. 喷雾干燥机械2022年全球行业分析报告
  7. Linux locate模糊查询,linux命令: 两个查找工具 locate,find(示例代码)
  8. Linux - 查看磁盘空间占用
  9. Xray-强大的漏洞扫描工具
  10. 1.万人直播架构与CDN网络