欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

MySQL-InnoDB-MVCC多版本并发控制

程序员文章站 2022-05-07 12:29:06
一、MySQL可重复读级别下,因为MVCC引起的BUG,下图1为相应的Java代码,其中事务1的生命周期最长,循环开启的事务2、3、4。。。与事务1并行 ,数据的读取只会成功一次,后面的读不到新增数据,从而出现空指针异常,但是当事务隔离级别为读提交时,程序会正常执行 图1 解决方案:将方法userR ......

一、mysql可重复读级别下,因为mvcc引起的bug,下图1为相应的java代码,其中事务1的生命周期最长,循环开启的事务2、3、4。。。与事务1并行 ,数据的读取只会成功一次,后面的读不到新增数据,从而出现空指针异常,但是当事务隔离级别为读提交时,程序会正常执行

MySQL-InnoDB-MVCC多版本并发控制

                                        图1

解决方案:将方法userremoteservice.adduser和userbasecontext.getuserbasebyuserid放在两个方法中,避免事务的并发问题

 

二、mvcc简介:multiversion concurrency control,多版本并发控制机制,行级锁的一个变种, 但是它在很多情况下避免了加锁操作, 因此开销更低,实现了非阻塞的读操作,只在read committed和repeatable read两个隔离级别下工作,因为read uncommitted总是读取最新的数据行,而serializable则会对所有读取的行都加锁

 

三、数据行隐藏字段

6字节的data_trx_id 标记了最新更新这条行记录的transaction id,每处理一个事务,其值自动+1

7字节的data_roll_ptr 指向当前记录项的rollback segment的undo log记录,找之前版本的数据就是通过这个指针

6字节的db_row_id,当由innodb自动产生聚集索引时,聚集索引包括这个db_row_id的值,否则聚集索引中不包括这个值.,这个用于索引当中

delete bit位用于标识该记录是否被删除,这里的不是真正的删除数据,而是标志出来的删除。真正意义的删除是在commit的时候

 

对于有有三个字段id、name、balance的表,其中id为主键,实际的拥有的列如下

MySQL-InnoDB-MVCC多版本并发控制

                                                                                                    图2

 

四、具体的执行过程:

select:innodb检查每行数据,确保他们符合两个标准:

1、innodb只查找版本早于当前事务版本的数据行(也就是数据行的版本必须小于等于事务的版本),这确保当前事务读取的行都是事务之前已经存在的,或者是由当前事务创建或修改的行

2、行的删除操作的版本一定是未定义的或者大于当前事务的版本号,确定了当前事务开始之前,行没有被删除

符合了以上两点则返回查询结果。

insert:innodb为每个新增行记录当前系统版本号作为创建id,该操作没有回滚指针,因为不存在历史版本

delete:innodb为每个删除行的记录当前系统版本号作为行的删除id。

update:innodb复制了一行。这个新行的版本号使用了系统版本号。它也把系统版本号作为了删除行的版本

 

事务执行过程中,只有在第一次真正修改记录时(比如使用insert、delete、update语句),才会被分配一个单独的事务id,这个事务id是递增的,下面以update为例说明

begin->用排他锁锁定该行->记录回滚数据到undo log->将修改前的行标记为删除,写事务编号->新增行保存修改后的值,写事务编号,回滚指针指向undo log中的修改前的行->记录修改后数据redo log->commit->后台线程将数据写磁盘

MySQL-InnoDB-MVCC多版本并发控制

                                                                                                                                   图3

优点:
保存这两个额外系统版本号,使大多数读操作都可以不用加锁。这样设计使得读数据操作很简单,性能很好。

缺点:
每行纪录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。

 

五、read view

1.判断当前版本数据项是否可见

2.提交读的隔离级别下,事务开始后到结束前,每次读取数据都会生成一个read view,而可重复读的隔离级别,只有事务开始后第一次读取数据,才生成read view

2.在innodb中, 每创建一个新事务, 存储引擎都会将当前系统中的活跃事务列表创建一个副本(read view), 副本中保存的是系统中当前不应该被本事务看到的其他事务id列表

3.当用户在事务中要读取某行记录的时候, innodb会将该行当前的版本号与该read view进行比较

4.比较流程:read view中最早的事务id为tmin,最迟的事务id为tmax,当前事务id为t0

MySQL-InnoDB-MVCC多版本并发控制

                                                                                             图4

 

 

参考文章

https://www.cnblogs.com/williamjie/p/9492810.html
https://www.jianshu.com/p/db334404d909
https://juejin.im/post/5c9b1b7df265da60e21c0b57