MySQL——一致性非锁定读(快照读)&MVCC
MySQL——一致性非锁定读(快照读)
MySQL数据库中读分为一致性非锁定读、一致性锁定读
- 一致性非锁定读(快照读),普通的SELECT,通过多版本并发控制(MVCC)实现。
- 一致性锁定读(当前读),SELECT ... FOR UPDATE/SELECT ... LOCK IN SHARE MODE/INSERT/UPDATE/DELETE,通过锁实现。
本文主要介绍一下一致性非锁定读,简单看一下2个场景:
-- 创建表tx
create table t (id int auto_increment,name varchar(10),primary key(id)) engine=innodb;
-- 写入数据
insert into t(name) values ('a');
场景一
| session1 | session2 | |
|---|---|---|
| 查看事务隔离级别 | select @@session.tx_isolation; ![]() |
select @@session.tx_isolation; ![]() |
| 查看数据 | select * from t where id=1; ![]() |
select * from t where id=1; ![]() |
| 开启事务 | begin; | begin; |
| 会话1更新数据 | update t set name='b' where id=1; ![]() |
|
| 查看数据 | select * from t where id=1; ![]() |
select * from t where id=1; ![]() |
| 会话1事务提交 | commit; | |
| 会话2查看数据 | select * from t where id=1; ![]() |
|
| 会话2事务提交 | commit; |
场景二
| session1 | session2 | |
|---|---|---|
| 查看事务隔离级别 | select @@session.tx_isolation; ![]() |
select @@session.tx_isolation; ![]() |
| 查看数据 | select * from t where id=1; ![]() |
select * from t where id=1; ![]() |
| 开启事务 | begin; | begin; |
| 会话1更新数据 | update t set name='c' where id=1; ![]() |
|
| 查看数据 | select * from t where id=1; ![]() |
|
| 会话1事务提交 | commit; | |
| 会话2查看数据 | select * from t where id=1; ![]() |
|
| 会话2事务提交 | commit; |
场景一、二session1 分别对数据进行修改,事务隔离级别为可重复读(Repeatable read);session2进行读取,场景二读取到了session1修改的数据;
是不是有点困惑?这就是所谓的MySQL一致性非锁定读,通过MVCC实现,细看场景一、二的不同,发现场景二session2在事务开启之后session1事务提交之前从未读取数据,这就是场景一、二结果不一样的原因(即数据版本的选取)。
一致性非锁定读是指InnoDB存储引擎通过多版本控制的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行DELETE或UPDATE操作,此时的读取操作不会因此去等待行上的锁释放。相反地,InnoDB存储引擎会去读取行的一个快照数据。
一致性非锁定读之所以成为非锁定读,因为不需要等待访问数据行的X锁的释放。快照数据是指该行数据的之前版本,改实现通过undo log完成。而undo是用来事务回滚的数据,因此快照数据本身没有额外的开销;此外快照数据不需要上锁,因为没有事务需要对历史数据进行修改操作。
一致性非锁定读机制极大的提高了数据库的并发性。在InnoDB存储引擎的默认设置下,这个默认的读取方式,即读取不会占用和等待表上的锁(SELECT ... FOR UPDATE/SELECT ... LOCK IN SHARE MODE除外);一致性行非锁定读,用到到数据的之前的历史版本,可能会有多个历史版本,由此带来的并发控制,就是大名鼎鼎的多版本并发控制(MVCC)。
因为MYSQL数据库InnoDB存储引擎支持4中事务隔离级别,并不是每个事务隔离级别都采用一致性非锁定读。
在事务隔离级别已提交读(Read committed)、可重复读(Repeatable read InnoDB存储引擎默认的事务隔离级别)下,InnoDB存储引擎采用一致性非锁定读。
- 已提交读(Read committed):每次普通的SELECT(非SELECT ... FOR UPDATE/SELECT ... LOCK IN SHARE MODE)都会读取数据的最新行版本(每次创建最新快照read view)。
- 可重复读(Repeatable read):事务开启后第一次普通的SELECT(非SELECT ... FOR UPDATE/SELECT ... LOCK IN SHARE MODE)读取最新行版本(第一次创建快照,以后沿用read view)。
对于Innodb存储引擎的聚集索引即数据行存在2个隐藏的列trx_id事务id、roll_pointer回滚指针,trx_id用来一致性非锁定读判断数据是否可见,roll_pointer用于事务回滚(指向数据的上一个版本);undo log中存在数据的版本链。

对于ReadView的实现:ReadView创建是根据当前活跃事务的列表,生成一个ReadView数据结构,包含当前所有活跃的事务id的ids集合、maxId最大事务id、minId最小事务id;
当读取数据时,数据行的事务id为trx_id
- trx_id大于ReadView的maxId,则表示此trx_id的事务在生成ReadView之后开启的,数据的当前版本不可见
- trx_id小于ReadView的minId,则表示此trx_id的事务在生成ReadView之前开启并提交的,数据的当前版本可见
- trx_id处于minId与maxId之间的,需判断trx_id是否在ids里,在则数据的当前版本不可见,不在则数据的当前版本可见
上面简述了ReadView的原理和在事务隔离级别已提交读(Read committed)、可重复读(Repeatable read)的生成策略;接下来回顾一下本文开始的场景;
- 场景一,session2的事务隔离级别为可重复读,ReadView在第一次SELECT时创建,此时session1的事务已开启且尚未提交处于活跃状态;ReadView中ids含session1的trx_id,在之后读取的时复用ReadView(ids含session1的trx_id),即使session1的事务提交后,session1修改的数据仍不可见。
- 场景一,session2的事务隔离级别为可重复读,ReadView在第一次SELECT时创建,此时session1的事务已提交;ReadView中ids不含session1的trx_id,session1修改的数据可见。
trx_id事务id,trx_id的生成时机、策略
-- MySQL查看当前事务的trx_id
SELECT tx.trx_id FROM information_schema.innodb_trx tx WHERE tx.trx_mysql_thread_id = connection_id()


- 通过演示可知事务trx_id:
- trx_id全局唯一,递增
- 事务trx_id的在一致性锁定读(当前读),SELECT ... FOR UPDATE/SELECT ... LOCK IN SHARE MODE/INSERT/UPDATE/DELETE时生成,且每个事务只有一个;对于一致性非锁定读(快照读),普通的SELECT,若当事务尚未分配trx_id会生成一个伪trx_id(只读事务max_trx_id 2^48=421982752402168)(不涉及对数据的增删改),若当前事务已经分配trx_id则复用
上面介绍了trx_id,以便于理解Mysql数据库InnoDB存储引擎一致性非锁定读的ReadView。
本文简单简单描述了一下MySQ InnoDB存储引擎的一致性非锁定读以及实现原理MVCC,因本人能力有限,如有不妥之处请多多指教。
MySQL——一致性非锁定读(快照读)&MVCC的更多相关文章
- MySQL一致性非锁定读
一致性非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过多版本控制(multi versionning)的方式来读取当前执行时间数据库中行的数据,如果读取的行 ...
- mysql 快照读MVCC
mysql的读分快照读和当前读 快照读 是指写的同时,读不阻塞,达到并发的作用 这时候的读 是 记录的历史版本,存在于undo里,当然回滚时就的也是这个undo 当执行一条update语句时,记录本身 ...
- [MySQL] 一致性读分析
MySQL MVCC MySQL InnoDB存储引起实现的是基于多版本的并发控制协议---MVCC(Multi-Version Concurrency Control),基于锁的并发控制,Lock- ...
- Innodb中的快照读和当前读
一.前言 上篇文章记录了对MVCC的相关理解,其中有提到快照读.其实在MVCC并发控制中,读操作可以分为两类:快照读(snapshot read)和当前读(current read) 二.什么是快 ...
- MySQL 学习笔记(二)MVCC 机制
之前在讲 MySQL 事务隔离性提到过,对于写操作给读操作的影响这种情形下发生的脏读.不可重复读.虚读问题.是通过MVCC 机制来进行解决的,那么MVCC到底是如何实现的,其内部原理是怎样的呢?我们要 ...
- MySQL中一致性非锁定读
一致性非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过多版本控制(multi versionning)的方式来读取当前执行时间数据库中行的数据,如果读取的行 ...
- 【MySQL】当前读、快照读、MVCC
当前读: select...lock in share mode (共享读锁) select...for update update , delete , insert 当前读, 读取的是最新版本, ...
- MySQL 一致性读 深入研究
一致性读,又称为快照读.使用的是MVCC机制读取undo中的已经提交的数据.所以它的读取是非阻塞的. 相关文档:http://dev.mysql.com/doc/refman/5.6/en/innod ...
- MySQL 一致性读 深入研究 digdeep博客学习
http://www.cnblogs.com/digdeep/p/4947694.html 一致性读,又称为快照读.使用的是MVCC机制读取undo中的已经提交的数据.所以它的读取是非阻塞的. 相关文 ...
随机推荐
- AWS SDK 使用说明
AWS 的Python SDK包名为 boto3, 可以使用命令pip install boto3安装使用 BOTO3中的基本概念 boto3提供了两个级别的接口来访问AWS服务:High Level ...
- 通俗易懂浅谈理解ES6类this不同指向问题
1. class Btn{ //定义的一个类 constructor(id){ // constructor是一个构造函数,是一个默认方法,通过 new 命令创建对象实例时,自动调用该方法.一个类必须 ...
- Linux的内部命令和外部命令
为了提高系统运行效率,将经常使用的轻量的命令在系统启动时一并加载这些命令到内存中供shell随时调用,这部分命令即为内部命令.反之,只有当被调用时才会被硬盘加载的这部分命令即为外部命令. 内部命令实际 ...
- 【Mycat】Mycat核心开发者带你轻松掌握Mycat路由转发!!
写在前面 熟悉Mycat的小伙伴都知道,Mycat一个很重要的功能就是路由转发,那么,这篇文章就带着大家一起来看看Mycat是如何进行路由转发的,好了,不多说了,我们直接进入主题. 环境准备 软件版本 ...
- 402. 移掉K位数字
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k.num 不会包含任何前导零.示例 1 : 输入: num ...
- 基于FFmpeg的Dxva2硬解码及Direct3D显示(三)
初始化Direct3D 目录 初始化Direct3D 创建Direct3D物理设备对象实例 创建Direct3D渲染设备实例 创建Direct3D视频解码服务 Direct3D渲染可以通过Surfac ...
- 三:redis启动后的基础知识
Redis启动后的杂项基础知识 1.单进进程 单进程模型来处理客户端的请求.对读写等事件的响应是通过对epoll函数的包装来做到的.Redis的实际处理速度完全依靠主进程的执行效率 Epo ...
- [原题复现]2018护网杯(WEB)easy_tornado(模板注入)
简介 原题复现: 考察知识点:模板注入 线上平台:https://buuoj.cn(北京联合大学公开的CTF平台) 榆林学院内可使用信安协会内部的CTF训练平台找到此题 [护网杯 2018]eas ...
- MySQL第01课- CentOS + 单实例MySql编译安装总结
2016年2月,从oracle转向MySql ,碰上几个坑,特此记录 总结 1.注意环境变量.配置文件,操作过程不能出错 2.相比rpm方式安装,编译安装方式可以指定安装路径,再说安装是简单活,将来安 ...
- python菜鸟教程学习5: python运算符
算术运算符: 整除符号//:向下取接近商的整数 加+ 减- 乘* 除/ 取余% 幂** 比较运算符: 等于== 不等于!= 大于> 小于< 大于等于>= 小于等于<= 赋值运算 ...






