目录

一、事务的隔离级别

二、mysql怎么实现的可重复读

举例说明MVCC的实现

MVCC逻辑流程-插入

MVCC逻辑流程-删除

MVCC逻辑流程-修改

MVCC逻辑流程-查询

三、幻读

快照读和当前读

四、如何解决幻读

事务隔离级别有四种,mysql默认使用的是可重复读,mysql是怎么实现可重复读的?为什么会出现幻读?是否解决了幻读的问题?

一、事务的隔离级别

Read Uncommitted(未提交读)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。读取未提交的数据,也被称之为脏读(Dirty Read)。该级别用的很少。

Read Committed(提交读)

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变,换句话说就是事务提交之前对其余事务不可见。这种隔离级别也支持不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select查询可能返回不同结果。

Repeatable Read(可重复读)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题(mysql彻底解决了幻读问题?请往下看)。

Serializable(可串行化)

这是最高的隔离级别,它强制事务都是串行执行的,使之不可能相互冲突,从而解决幻读问题。换言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

事务隔离级别

脏读

不可重复读

幻读

读未提交(read-uncommitted)

不可重复读(read-committed)

可重复读(repeatable-read)

串行化(serializable)

在MySQL的众多存储引擎中,只有InnoDB支持事务,所有这里说的事务隔离级别指的是InnoDB下的事务隔离级别。

二、mysql怎么实现的可重复读

MVCC多版本并发控制(Multi-Version Concurrency Control)是MySQL中基于乐观锁理论实现隔离级别的方式,用于实现读已提交和可重复读取隔离级别。

在《高性能MySQL》中对MVCC的解释如下

举例说明MVCC的实现

新建一张表test_zq如下

id

test_id

DB_TRX_ID

DB_ROLL_PT

MVCC逻辑流程-插入

在插入数据的时候,假设系统的全局事务ID从1开始,以下SQL语句执行分析参考注释信息:

begin;-- 获取到全局事务ID

insert into `test_zq` (`id`, `test_id`) values('5','68');

insert into `test_zq` (`id`, `test_id`) values('6','78');

commit;-- 提交事务

复制代码

当执行完以上SQL语句之后,表格中的内容会变成:

id

test_id

DB_TRX_ID

DB_ROLL_PT

5

68

1

NULL

6

78

1

NULL

可以看到,插入的过程中会把全局事务ID记录到列 DB_TRX_ID 中去

MVCC逻辑流程-删除

对上述表格做删除逻辑,执行以下SQL语句(假设获取到的事务逻辑ID为 3)

begin;--获得全局事务ID = 3

delete test_zq where id = 6;

commit;

复制代码

执行完上述SQL之后数据并没有被真正删除,而是对删除版本号做改变,如下所示:

id

test_id

DB_TRX_ID

DB_ROLL_PT

5

68

1

NULL

6

78

1

3

MVCC逻辑流程-修改

修改逻辑和删除逻辑有点相似,修改数据的时候 会先复制一条当前记录行数据,同事标记这条数据的数据行版本号为当前是事务版本号,最后把原来的数据行的删除版本号标记为当前是事务。

执行以下SQL语句:

begin;-- 获取全局系统事务ID 假设为 10

update test_zq set test_id = 22 where id = 5;

commit;

复制代码

执行后表格实际数据应该是:

id

test_id

DB_TRX_ID

DB_ROLL_PT

5

68

1

10

6

78

1

3

5

22

10

NULL

MVCC逻辑流程-查询

此时,数据查询规则如下:

查找数据行版本号早于当前事务版本号的数据行记录

也就是说,数据行的版本号要小于或等于当前是事务的系统版本号,这样也就确保了读取到的数据是当前事务开始前已经存在的数据,或者是自身事务改变过的数据

查找删除版本号要么为NULL,要么大于当前事务版本号的记录

这样确保查询出来的数据行记录在事务开启之前没有被删除

根据上述规则,我们继续以上张表格为例,对此做查询操作

begin;-- 假设拿到的系统事务ID为 12

select * from test_zq;

commit;

复制代码

执行结果应该是:

id

test_id

DB_TRX_ID

DB_ROLL_PT

6

22

10

NULL

这样,同一个事务中,就实现了可重复读。

三、幻读

什么是幻读,如下:

InnoDB实现的RR通过mvcc机制避免了这种幻读现象。

另一种幻读:

姑且把左边的事务命名为事务A,右边的命名为事务B。

事务B执行后,在事务A中查询没有查到B添加的数据行,这就是可重复读。

但是,在事务A执行了update后,再查询时就查到了事务A中添加的数据,这就是幻读。

这种结果告诉我们其实在MySQL可重复读的隔离级别中并不是完全解决了幻读的问题,而是解决了读数据情况下的幻读问题。而对于修改的操作依旧存在幻读问题,就是说MVCC对于幻读的解决是不彻底的。

快照读和当前读

出现了上面的情况我们需要知道为什么会出现这种情况。在查阅了一些资料后发现在RR级别中,通过MVCC机制,虽然让数据变得可重复读,但我们读到的数据可能是历史数据,不是数据库最新的数据。这种读取历史数据的方式,我们叫它快照读 (snapshot read),而读取数据库最新版本数据的方式,叫当前读 (current read)。

select 快照读

当执行select操作是innodb默认会执行快照读,会记录下这次select后的结果,之后select 的时候就会返回这次快照的数据,即使其他事务提交了不会影响当前select的数据,这就实现了可重复读了。快照的生成当在第一次执行select的时候,也就是说假设当A开启了事务,然后没有执行任何操作,这时候B insert了一条数据然后commit,这时候A执行 select,那么返回的数据中就会有B添加的那条数据。之后无论再有其他事务commit都没有关系,因为快照已经生成了,后面的select都是根据快照来的。

当前读

对于会对数据修改的操作(update、insert、delete)都是采用当前读的模式。在执行这几个操作时会读取最新的版本号记录,写操作后把版本号改为了当前事务的版本号,所以即使是别的事务提交的数据也可以查询到。假设要update一条记录,但是在另一个事务中已经delete掉这条数据并且commit了,如果update就会产生冲突,所以在update的时候需要知道最新的数据。也正是因为这样所以才导致幻读。

在快照读读情况下,mysql通过mvcc来避免幻读。

在当前读读情况下,mysql通过next-key来避免幻读

四、如何解决幻读

很明显可重复读的隔离级别没有办法彻底的解决幻读的问题,如果我们的项目中需要解决幻读的话也有两个办法:

使用串行化读的隔离级别

MVCC+next-key locks:next-key locks由record locks(索引加锁/行锁) 和 gap locks(间隙锁,每次锁住的不光是需要使用的数据,还会锁住这些数据附近的数据)的结合,next-key lock 会锁定范围和自身行,比如select...where id<6,锁定的是小于6的行和等于6的行

Next-Key Lock即在事务中select时使用如下方法加锁,这样在另一个事务对范围内的数据进行修改时就会阻塞:

select * from table where id<6 lock in share mode;--共享锁

select * from table where id<6 for update;--排他锁

实际上很多的项目中是不会使用到上面的两种方法的,串行化读的性能太差,而且其实幻读很多时候是我们完全可以接受的。

关于next-key locks请参考https://www.cnblogs.com/zhoujinyi/p/3435982.html

参考文章:

https://juejin.im/post/5c68a4056fb9a049e063e0ab

https://zhuanlan.zhihu.com/p/35500144

https://www.jianshu.com/p/69fd2ca17cfd

《高性能MySQL》

mysql串行化防幻读原理_透彻解读mysql的可重复读、幻读及实现原理相关推荐

  1. mysql安装原理_全面解读MySQL主从复制,从原理到安装配置

    为什么需要主从复制? 1.在业务复杂的系统中,有这么一个情景,有一句sql语句需要锁表,导致暂时不能使用读的服务,那么就很影响运行中的业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出现了 ...

  2. mysql的count函数类型是什么意思_详细解读MySQL中COUNT函数的用法

    MySQL的COUNT函数是最简单的功能,非常有用的计算,预计由一个SELECT语句返回的记录数. 要了解COUNT函数考虑的EMPLOYEE_TBL的的表具有以下记录: mysql> SELE ...

  3. 脏读,不可重复读,幻读区别

    脏读 脏读又称无效数据读出.一个事务读取另外一个事务还没有提交的数据叫脏读. 例如:事务T1修改了一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改后的数据,之后事务T1因为某种原因Roll ...

  4. Mysql学习笔记之事务详解(读未提交、读以提交、可重复读、串行化读)

    文章目录 1.事务概述 2.事务特性 3.事务隔离级别 4.演示事务 4.1.演示读未提交 4.2.演示读已提交 4.3.演示可重复读 4.4.演示串行化读 1.事务概述 什么是事务? 一个事务是一个 ...

  5. 快速理解 脏读(未提交读),提交读(不可重复读), 可重复读, 可串行化 和 幻读

    脏读(未提交读): 正在执行的事务 读取到其他事物未提交的数据 A事务 B事务 开始事务 开始事务 查询小明年龄 是30岁 查询用户列表 共100条数据 查询用户列表 共100条数据 修改小明的年龄为 ...

  6. 隔离级别(未提交读、提交读、可重复读、可串行化)、多版本并发控制、Next-Key Locks(Record Locks、Gap Locks)

    1. 隔离级别 1.1 未提交读(READ UNCOMMITTED) 事务中的修改,即使没有提交,对其它事务也是可见的. 1.2 提交读(READ COMMITTED) 一个事务只能读取已经提交的事务 ...

  7. 事务的隔离级别(未提交读、提交读、可重复读、可串行化)

    SQL有四种隔离级别,分别为未提交读(read uncommited).提交读(read commited).可重复读(repeatable read).可串行化(serializable). 一.未 ...

  8. mysql可串行化读音,Oracle与MySQL中“可串行化”的对比测试

    Oracle与MySQL中"可串行化"的对比测试 Oracle与MySQL中"可串行化"的对比测试 Thomas Kyte 在"Oracle 9i&a ...

  9. MySQL事务的可串行化

    可串行化--SERIALIZABLE 事务的最高级别,在每个读的数据行上,加上锁,使之不可能相互冲突,因此,会导致大量的超时现象 设置b账户,事务的隔离级别 B账户,首先,将b账户的隔离级别设置为SE ...

最新文章

  1. Spring Boot常见企业开发场景应用、自动配置原理结构分析
  2. os项目icon和default 等相关图标命名规则和大小设置
  3. 苹果6s怎么连不上服务器未响应,iphone6s无法连接app store 苹果6s连不上app store解决方法...
  4. oracle 删除时间段的,oracle SQL如何从日期中删除时间
  5. nginx php fpm 日志,nginx下php-fpm不记录php报错日志怎么办?
  6. 一个我自己建的程序员资料分享站
  7. JDBC和数据库连接池的关系
  8. 英语中的完成时态的比较
  9. 小米5USB 计算机连接,小米手机连接电脑不显示usb选项
  10. win10如何删除计算机用户,在WIN10账户下怎么删除administrator账户
  11. 记录:前端框架Bootstrap学习使用之组件——Collapse(折叠)
  12. 7-3 IP地址转换分数 20
  13. Excel分组行转列
  14. python爬取豆瓣电影top250_用Python爬取豆瓣电影TOP250分析
  15. win服务器系统路由器,Windows server 2012 之路由功能
  16. 网关在物联网系统里面起着很重要的核心作用
  17. android usb采集卡,USB HDMI直播采集卡1805怎么用?
  18. python权限管理设置_python权限管理框架
  19. 李宏毅深度学习——机器终身学习
  20. 天狼50教学中部分英文缩写的含义

热门文章

  1. Cocos2d-x Lua cc ccsccui区别和使用
  2. 大热的政务云该怎么建,也许这家厂商有绝对优势
  3. Biome-BGC生态系统模型与Python融合技术
  4. 前端小知识:字体 - monospace vs monovolume 的区别
  5. 基于AM335x裸机开发例程使用手册
  6. SAP 会计凭证更改(FB02) 配置及注意事项
  7. 【数学建模学习笔记【集训十天】之第九天】
  8. 反向链接 反向代理_妇女与反向渠道
  9. hbase时间范围分页查询优化实践
  10. 手动下载maven插件到本地仓库