`
roverll
  • 浏览: 14010 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

mysql innodb mvcc 读一致性(Repeatable Read)通俗笔记

阅读更多
InnoDB 的 MVCC 和oracle 还是有区别,没有oracle那么纯粹,很简单可以体现在oracle 我可以直接flashback查询,但是InnoDB不行。 oracle 是怎么做MVCC 就没有具体了解了,快2年没有用oracle了,肯定是undo log ,redo log 等结构更强大。


InnoDB MVCC提供了两个关键功能,一:写不阻塞读 。  二:读一致性。一下主要介绍一下InnoDB实现读一致性需要达到的效果大家容易理解,要实现Repeatable Read 事务隔离级别,就是InnoDB实现到什么程度了,我感觉开发人员比较容易糊涂,我也是。

    附:写不阻塞读,个人感觉只要是MVCC的,肯定就是写不阻塞读了,MVCC给我们程序员提供的最好东西也就是写不阻塞读,不过Mysql InnoDB 在某些情况下写会阻塞读,下文会写到。

InnoDB engine 有一个全局的 Transaction ID (事务ID,下文用trx_id 表示,即当前版本)  使用show engine innodb status 可以看到。

写在前面:以下描述过于繁杂,我表述也成问题,如果把 事务ID 当版本ID 来读就更好理解。

每开启一个事务的时候 trx_id 就会自增保证每个事务都有自己的trx_id,事务内多步操作不会每个操作都增长(废话) 。当 autocommit = 1  的时候 每个select 都会让trx_id 涨一,这时 trx_id 的增长当会受查询缓存影响,如查询两次没有涨那肯定就是查询缓存起作用了,连续两个select 查询结果一样,后一个是读得查询缓存。

我得理解:每个条数据都记录了一个事务id,就是该数据最后被一次修改的事务ID。

再稍微提下一undo log,redo log。网上一找一堆,我把自己认为合理的说一下,这个undo log和读一致性有关,有必要提一下:
来个找到的定义,写得比较好就直接贴出来:
redo log:重做日志,就是每次mysql在执行写入数据前先把要写的信息保存在重写日志中,但出现断电,奔溃,重启等等导致数据不能正常写入期望数据时,服务器可以通过redo_log中的信息重新写入数据。
undo log:撤销日志,与redo log恰恰相反,当一些更改在执行一半时,发生意外,而无法完成,则可以根据撤消日志恢复到更改之前的壮态。
以一个update 操作为例子:
首先记录undo-log,把本次修改的字段原始值记录下来(包括旧版本的事务id,即修改前的事务id,读一致性里面这个比较重要)
然后在本条记录上进行修改(具体看参考文献)(映像oracle 是复制一条新的记录,标记为update操作的版本号,可能这就是oracle的MVCC那么纯粹,可以flashbak 查询而mysql InnoDB 不行的原因,oracle查询带着版本号就行,我猜mysql 就得一层层的查redo-log,性能上面肯定就不行,这个功能也就做不了了)
修改后写redo-log(包括有新版本事务id)
接着就commit;

undo redo log 说了就说 关于InnoDB如何实现MVCC 读一致性的:

每个select 都会产生一个 read view
在事务开启的时候创建一个记录之前已经是活跃的事务(还没有提交的事务)trx_id 列表,这个就是 read view,在事务结束前是不会变的,代表着当前的版本!

设其中最早的事务id为trx_id_low,最迟的事务id为trx_id_up
本操作所在的事务id(版本号)w为 trx_id_cur

首先:这个trx_id_cur 肯定大于trx_id_up ,版本号是唯一的,递增的。

查询的时候,查到当行的记录的trx_id 为 trx_id_row 。

首先这个trx_id_row 可能比trx_id_cur大,那就比trx_id_up 也大了,场景:
    读的时候其他线程又新起了一个事务,插入了一条数据还commit了。版本号就比当前操作大了,这种数据肯定不应该可见,不然读到后面版本提交的数据那何来MVCC。
以上就是很多博客直接说的
条件1 trx_id_row  > trx_id_up(不是很好理解),但是算法就是这样的(由于不可见到条件5去查undo log)

条件2 如果trx_id_row < trx_id_low  由于trx_id_low < trx_id_up < trx_id_cur  所以说明该行数据在本次事务开始已经提交了,所以可见,直接返回到结果集。

条件3 如果  trx_id_low  <= trx_id_row  <= trx_id_up
就应该遍历对当前  read view 的 list
     如果包含trx_id_row,说明当前事物开始的时候,这个事物还没有提交,现在提交了肯定对与当前事物来说不可见,毕竟当前事物开始的时候它还没有被提交(到条件5去查undo log)。
     如果不包含就没有问题了,因为trx_id_row  < trx_id_up  <  trx_id_cur , 比当前版本小,又是提交了的,就是可见的了(这个可以理解吧),直接加入返回结果集了。

条件5 对于所有不可见的 trx_id_row 就通过 该行主键(应该是oracle ROW_ID 那种)去查undo_log ,找到undo log 中最新一个版本,把它的trx_id 赋值给当前的trx_id_row  再跑一次判断,直到满足条件就返回。为什么需要循环跑?就是条件1的极端情况,本事务启动后,先后有两个事务修改过当前行的数据,最新一条redo log 的事务id 都 > trx_id_cur > trx_id_up 肯定需要再循环判断,找到具体需要的版本 ,这时一个类似链式的过程(当然具体数据结构我不知道,再次验证innoDB 不能带版本查询的原因了)

我觉得有点需要提(由于这个在源码剖析的方法外面,别人没有提):trx_id_row = trx_id_cur 的时候是本事务内的操作,对本事务肯定可见了。

完。

关于一直说mysql 不能按版本查询 ,一般oracle 的flashback 查询都是程序员犯错的一个补救措施,回滚数据。不直接,说两个oracle 可以但是mysql不行的查询场景更直观:
1、写操作依赖本表数据,造2个例子(不恰当再换) :
a例子:update table_a  a set a_col1 = (select a_col2 from table_a aa where a.col3 = aa.col3 + 1 )(oracle 就可以,这才是真MVCC)
b例子:insert into a select * from a;
2、a 表有写操作未提交,使用a表被操作加锁的行去更新b表会被锁(又不算真MVCC,oracle又可以):例子:
事务1:
update a set col1 = ? where fk  =1;
事务2
update b set cols = (select sum(col1) from a where a.fk = b.id)

事务1没有提交,事务2会阻塞,这其实就是写阻塞读了。

当然这些缺点我们可以在应用层(java)中自己处理,无伤大雅。

具体参考了别人的源码剖析:http://hi.baidu.com/gao_dennis/item/1f133311f50a94423a176ef5

我就是用一个更直接的话表述出来了,当然我得表述总是不清楚,轻拍!
0
0
分享到:
评论

相关推荐

    InnoDB引擎MVCC实现原理.pptx

    InnoDB 引擎支持四种隔离级别:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。每种隔离级别都有其特点和应用场景。 锁 InnoDB 引擎中的锁机制包括 Record Locks、Gap Locks 和 Next-Key ...

    MySQL技术内幕InnoDB存储引擎-读书笔记.pdf

    MySQL技术内幕InnoDB存储引擎-读书笔记.pdf

    MySQL内核:InnoDB存储引擎 卷1.pdf.zip

    1. **事务支持**:InnoDB支持事务的四种隔离级别,包括读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ,MySQL默认级别)和串行化(SERIALIZABLE)。这使得InnoDB能保证数据...

    MySQL Innodb 索引原理详解

    ### MySQL Innodb 索引原理详解 #### 1. 各种树形结构 在深入探讨MySQL Innodb索引之前,我们先了解几种基本的树形数据结构,包括二叉搜索树、B树、B+树以及B*树。 ##### 1.1 搜索二叉树(Binary Search Tree) ...

    mysql innodb恢复数据工具.rar

    这是我从网上找到的mysql/mariadb对innodb表进行数据恢复的工具,实现从innodb的数据库文件中恢复数据,用于实现下面情况:1、直接下载了innodb数据库的文件,而不是导出其数据,想恢复数据时(需要有完整的文件,...

    Mysql 的InnoDB引擎相关读书笔记

    Mysql 的InnoDB引擎的相关笔记 1.0.MySQL架构到innoDB架构.md 1.1.0.InnoDB——简介.md 1.1.1.InnoDB——关键特性.md 1.2.0.InnoDB内存结构——缓冲池.md 1.2.1.InnoDB内存结构——log buffer.md 1.2.2.InnoDB内存...

    MySQL InnoDB Cluster安装.docx

    同时,为了保证数据一致性,应定期备份集群,并了解如何在发生问题时恢复数据。此外,监控网络连接也很关键,因为任何网络中断都可能导致集群中的节点失去联系。最后,确保所有安全措施都已到位,防止未经授权的访问...

    Mysql 高可用 InnoDB Cluster 多节点搭建过程

    Mysql 高可用 InnoDB Cluster 多节点搭建过程是指使用 Mysql 的 InnoDB Cluster 功能来搭建一个高可用性的集群环境。在这个过程中,我们将使用四台服务器,node01、node02、node03 作为集群节点,node04 作为管理...

    MySql Innodb 引擎特性详解

    1. **支持事务**:InnoDB支持四种不同的事务隔离级别,包括READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ以及SERIALIZABLE,能够提供ACID(原子性、一致性、隔离性、持久性)事务保障。 2. **行级锁定**:...

    mysql innodb类型数据库表 根据ibd文件获取表 space id

    mysql innodb类型数据库表 根据ibd文件获取表 space id,用于恢复innodb类型数据表数据

    MySQL体系结构及原理(innodb)图文完美解析

    当一个字段被定义为索引的一部分时,不允许设置为NULL是为了保持索引的完整性和一致性。如果允许NULL值,则会降低索引的效率,增加索引维护的复杂度。 #### 存储层级与性能 1. **存储设备分类** - **机械磁盘**...

    MySQL InnoDB小结1

    InnoDB存储引擎支持事务处理,提供了四种事务隔离级别:读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ,InnoDB默认级别)和串行化(SERIALIZABLE)。不同的隔离级别有不同...

    MySQL技术InnoDB存储引擎_姜承尧_第2版

    书中会详细讲解四种隔离级别——读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ,MySQL默认级别)和串行化(SERIALIZABLE),以及它们在并发控制中的区别和应用场景。...

    MySQL innodb 技术内幕

    InnoDB 存储引擎是 MySQL 的默认存储引擎,它支持外键、行锁、非锁定读、MVCC 等功能。InnoDB 存储引擎通过使用 MVCC 来获取高并发性,并且实现 SQL 标准的 4 种隔离级别,同时使用一种被称为 next-key locking 的...

    MySQL InnoDB 查询优化实现分析

    ### MySQL InnoDB 查询优化实现分析 #### 一、目的与背景 本文旨在深入探讨 MySQL + InnoDB 存储引擎在实现查询优化时所采取的方法及其内部机制。通过具体实例和详细的技术解析,揭示 InnoDB 如何高效处理各种查询...

Global site tag (gtag.js) - Google Analytics