mvcc浅析

1. 什么是MVCC?

  MVCC全称是 多版本并发控制 主要是为了提高数据库的并发性能。MVCC是一种并发控制的方法 一般在数据库管理系统中 实现对数据库的并发访问 在编程语言中 实现事务内存

多版本控制:值得是一种提高并发的技术 最早的数据库中 只有读读之间可以并发 读写 写读  写写都要阻塞。引入多版本控制器之后 只有写写之间相互阻塞 其他三种操作 是可以并行的 这样就可以大幅度的提高innodb的并发度。在内部实现过程中 innodb是在undolog中实现的 通过undolog可以找回数据的历史版本

MVCC在mysql中 的实现 主要是为了提高数据库的并发性能 用更好的方式去处理读-写冲突做到及时有读写冲突 也能不加锁 非阻塞并发读

 

2. 什么是当前读和快照读?

  当前读:update delete insert 这些操作都是当前读 加的是排他锁 原因是这些操作读取的是记录中最新的值 在读取的过程中 还要保证其他并发事务不能修改当前数据 会对读取的数据进行加锁

  快照读:像select操作就是快照读 即不加锁的非阻塞读;快照读的前提是 事务的隔离级别非串行级别。快照读可能读到的并不一定是最新的数据 有可能是之前的历史版本

 说白了 MVCC就是为了实现读-写冲突不加锁 而这个读就是快照读 而非当前读 当前读实际上是加锁的操作 是悲观锁的实现

 

3. 当前读 快照读和MVCC的关系

  1>  准确的说MVCC多版本并发控制 值得是维持一个数据的多版本 使得读写操作没有冲突

  2>  在mysql中 快照读 就是mysql为我们实现mvcc立项模型的一个具体非阻塞读功能 相对而言 当前读就是悲观苏的具体功能体现

 

4. MVCC能解决什么问题 好处是什么?

  1> 读-读: 不存在任何问题 也不需要任何并发控制

  2> 读-写: 有线程安全的问题 可能会造成事务隔离性问题 会遇到脏读 幻读 不可重复读等问题

  3> 写-写: 有线程安全的问题 可能会存在更新丢失问题 比如第一类更新丢失 第二类更新丢失

  Tip: 第一类更新丢失:事务A撤销时 把已经提交的事务B的更新数据覆盖了;第二类更新:事务A覆盖事务B已经提交的数据 造成事务B数据的丢失

MVCC的好处: 是一种用来解决读-写冲突的无锁并发控制 也就是为事务分配单项增长的时间戳 为每个修改保存一个版本 版本与事务时间戳关联 读操作只读该事物开始前的数据库快照 所以MVCC可以为数据库解决以下问题:

  1> 在并发读写数据库时 可以做到在读操作时 不用阻塞写操作 写操作也不用阻塞读操作 提高了数据库并发读写的性能

  2> 同时还可以解决脏读 幻读 不可重复读等事务隔离问题 但不能解决更新丢失数据问题

小结:总之MVCC就是为了解决 大牛们不满意只让数据库采用悲观锁这样性能不佳的形式去解决读-写冲突问题 而提出的方案 所以在数据库中 因为有了MVCC 我们可以形成两个组合 :

  MVCC + 悲观锁:MVCC解决读写冲突 悲观锁解决写写冲突

  MVCC + 乐观锁:MVCC解决读写冲突 乐观锁解决写写冲突

 

5. MVCC的实现原理

  MVCC的目的就是多版本并发控制 在数据库中的实现 就是为了解决读写冲突 它的实现原理 主要依靠记录中的3个隐式字段、undo日志、read view 来实现的

5.1 隐式字段

  每行记录 除了我们自定义的字段外 还有数据库隐式定义的 DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID 等字段

DB_TRX_ID:当前操作该记录的事务ID

DB_ROLL_PTR: 回滚指针 指向这条记录的上一个版本 配合undo日志使用

DB_ROW_ID: 隐含的自增ID(隐藏的主键)  数据库默认为改行记录生产的唯一隐式主键

 

6. undo 日志

  6.1 insert undolog: 代表事务在insert新纪录的时候 产生的 undo log,只在事务会滚时需要 并在在事务提交时可以被立即丢弃

  6.2 update undolog: 事务在进行update或者delete时产生的undolog 不仅在事务回滚时需要 在快照读时也需要;所以不能随便删除 只有在快速读或事务回滚不涉及改日志时 对应的日志才会被purge线程统一删除

  Tip: 不同事务或者相同事务 对同一记录的修改 会导致该记录的undo log成为一条记录版本线性表 及链表 undolog的链首就是最新的旧记录 链尾就是最早的旧记录

 

7. Read View简介

  read view就是事务进行快照读操作的时候 产生的读视图 在该事物执行的快照读的那一刻 会生成数据库系统当前的一个快照 记录并维护系统当前活跃事务的ID 越新的事务 事务ID越大

  read view主要是用来做可见性判断的 即当我们某个事物执行快照读的时候 对该记录创建一个read view读视图 把它比作条件用来判断事务能够看到那个版本的数据

 

8. 综述

  快照读的结果 非常依赖该事物首次出现快照读的位置 即某个事物中 首次出现快照读的地方非常关键 他有决定该事物后续快照读结果的能力

 案例1:

  mvcc浅析

 

案例2
  mvcc浅析

 

 表1和表2的区别仅在于表1 的事务B 在事务A修改金额之前 快照读过一次数据 而表2的事务B 在事务A提交之前没有进行过快照读 所以读到的数据为修改后的数据 这可以从侧面反映出 事务中首次出现快照读的位置 对事务数据的影响

 

9. RC RR级别下的innodb快照读有什么不同?
  正式read view生成时机的不同 从而造成了RC RR级别下 快照读结果的不同

  1> 在RR级别下的某个事物对某条记录的第一次快照读会创建一个快照 及read view 将当前系统活跃的其他事务记录起来 词汇在调用快照读的时候 还是使用当前事务在其他事务提交更新之前使用过的快照读 那么之后的快照读 使用的都是同一个read view 所以对之后的修改不可见

  2> 即RR级别之下 快照读生成的read view 会记录此时所有其他活动事务的快照 这些事务的修改 对应当前事务都是不可见的 而早于read view创建的事务 所做的修改 均可见

  3> 在RC级别之下的事务中 每次快照读 都会生成一个新的快照和一个新的read view 这就是我们在rc级别下的事务 可以看到别的事务提交更新的原因

Tip: 在RC隔离级别下 是每个快照读都会生成并获取最新的read view;而在RR级别下 则是同一个事务中的第一个快照读才会创建read view 之后的快照读 获取的都是同一个read view

 

mvcc浅析

上一篇:【工具箱】web http response响应头解决安全问题


下一篇:kafka-jstorm实时代码