之前已经转载过几篇相关的文章,此次基于mysql 5.7 版本,从测试和源码角度解释一下RR,RC级别为什么看到的数据不一样

先补充一下基础知识

基本知识

假设对于多版本(MVCC)的基础知识,有所了解。InnoDB为了实现多版本的一致读,采用的是基于回滚段的协议。

行结构

InnoDB表数据的组织方式为主键聚簇索引。由于采用索引组织表结构,记录的ROWID是可变的(索引页分裂的时候,Structure Modification Operation,SMO),因此二级索引中采用的是(索引键值, 主键键值)的组合来唯一确定一条记录。

无论是聚簇索引,还是二级索引,其每条记录都包含了一个DELETED BIT位,用于标识该记录是否是删除记录。除此之外,聚簇索引记录还有两个系统列:DATA_TRX_ID,DATA_ROLL_PTR。DATA _TRX_ID表示产生当前记录项的事务ID;

DATA _ROLL_PTR指向当前记录项的undo信息。

开启4个mysql客户端,client1 用来查看数据情况 , client2,client3,client4 更新数据

表结构

所有client 启动事务

执行 show engine innodb status\G  , 观察目前的事务信息

这里可以看到目前没有任何活动事务(select 不产生任何活动事务,只有insert ,update,delete 才会产生活动事务)

我们先在client2 执行一个insert sql,然后再在client1 看事务信息

我们可以看到client2 产生了12654 的活动事务, 我们继续再client3执行sql

client3 产生了一个12659的事务

我们从截图的角度看这2个事务

12659    -- 这是物理位置比较高的事务, mysql 本身里有专有名词叫 low_limit_id ,高水位

12654    --这是物理位置比较低的事务, up_limit_id ,低水位

接下来我们在client1 执行select查询

client2,client3还没有提交,这时候client1 只能获取到以前的旧数据

这时候client2,client3提交,再在client1查询

重点来了,这时候mysql产生了一份快照,这里叫read_view, 快照的结构是

read_view->creator_trx_id = 当前client1的事务id;

read_view->up_limit_id = 12654;

read_view->low_limit_id = 12659;

read_view->trx_ids = [12654,12659];

read_view->m_trx_ids = 2;

接下来,我们在client4执行insert操作,并马上commit提交,然后再在client1执行select查询

我们可以看到client4的修改虽然已经提交,但是client1还是看不到这个变化,那是因为:

low_limit_id;    /* 索引数据事务号 DATA_TRX_ID >= low_limit_id的记录,对于当前Read View都是不可见的 */

up_limit_id;    /* 索引数据事务号  DATA_TRX_ID< up_limit_id ,对于当前Read View都是可见的 */

刚才client4修改的时候产生的事务id是比12659还要大的一个数字, 没有查看,不知道具体数字,我们假设是12700这个数字

当产生read-view的时候, low_limit_id 是 12659,up_limit_id 是12654, 12700>12659 & 12654, 所以这些12654,12659对于那个read-view来说是看不见的

如果在client1 select 产生read-view 之前就执行client4的修改(和提交, 这时候client4的事务id, 我们假设就是一个比12654小的数字,如12600),12600<12654, 所以client4的修改对于当前read-view就是可视的

我们看看源码 read0types.h

那为什么事务隔离级别是RC级别的时候,重复上面的操作步骤, client1在client2,client3提交后select 的时候,就能马上查询到修改

我们看源码

ha_innodb.cc的ha_innobase::external_lock方法里

在RC级别的时候,每次都会关闭read-view并产生一份新的

最新文章

  1. form表单编码方式设置为multipart/form-data,后台参数出现乱码情况
  2. 第二天 django apache
  3. 【C++沉思录】句柄1
  4. 3种用组策略将域帐号加入本地管理员组的方法_jinifly_新浪博客
  5. 在 Perl 中使用 Getopt::Long 模块来接收用户命令行参数
  6. Quartz Scheduler(2.2.1) - Usage of JobDataMap
  7. MongoDB导出-导入-迁移
  8. Maven 设置Maven源/镜像
  9. CEF小白人系列2-DEV环境配置-Windows10+SDK+VS2015
  10. Git常用简介
  11. “浅入浅出”函数防抖(debounce)与节流(throttle)
  12. JS设计模式(13)状态模式
  13. 关于spring的一些注解
  14. jquery中siblings方法配合什么方法一起使用
  15. 外购半成品报SHORT问题(验货客户)
  16. shell:syntax error:unexpected end of file/Starting proxy www-balancer: cannot bind socket--转载
  17. “Hello World!”团队第七周召开的第六次会议
  18. ME.kkkK
  19. Django基础模板案例
  20. HMTL label标签

热门文章

  1. ubuntu下,python2.7安装mysqlldb驱动方法
  2. 十分钟搞定 pandas
  3. oracle mysql 比较
  4. mac安装brew简单方法
  5. 常用vi编辑器命令
  6. 为什么 EXISTS(NOT EXIST) 与 JOIN(LEFT JOIN) 的性能会比 IN(NOT IN) 好
  7. 42.输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S, 如果有多对数字的和等于S,输出两个数的乘积最小的。
  8. Matlab中的rectangle函数
  9. hdu 1394 逆序对(nlgn+o(n) )
  10. js&#183;&#183;BOM 浏览器对象模型