mysql mvcc 流程(Mysql MVCC机制原理详解)
mysql mvcc 流程
Mysql MVCC机制原理详解什么是mvcc
mvcc,全称multi-version concurrency control,即多版本并发控制。mvcc是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。
我们知道,一般情况下我们使用mysql数据库的时候使用的是innodb存储引擎,innodb存储引擎是支持事务的,那么当多线程同时执行事务的时候,可能会出现并发问题。这个时候需要一个能够控制并发的方法,mvcc就起到了这个作用。
mysql的锁和事务隔离级别
在理解mvcc机制的原理之前,需要先理解mysql的锁机制和事务的隔离级别,抛开myisam存储引擎不谈,就innodb存储引擎来说,分别有行锁和表锁两种锁,表锁就是一次操作锁住整张表,这样锁的粒度最大,但是性能也最低,不会出现死锁。行锁就是一次操作锁住一行,这样锁的粒度小,并发度高,但是会出现死锁。
innodb的行锁又分为共享锁(读锁)和排它锁(写锁),当一个事务对某一行加了读锁时,允许其他事务对这一行进行读操作,但是不允许进行写操作,也不允许其他事务对这一行执行加写锁,但是可以加读锁。
当一个事务对某一行加了写锁时,不允许其他事务对这一行进行写操作,但是可以读,同时不允许其他事务对这一行加读写锁。
下面来看一下mysql的事务隔离级别,分为以下四种:
- 读未提交:一个事务可以读到其他事务还没有提交的数据,会出现脏读。举个例子,有一张工资表,事务a先开启,然后执行查询id为1的员工的工资,假设此时的工资为1000,此时,事务b也开启,执行了更新操作,将id为1的员工工资减少了100,但是并未提交事务。此时再执行事务a的查询操作,可以读到事务b已经更新的数据,如果此时事务b发生回滚,事务a读到的就是“脏”数据。当事务a执行更新操作的话还可能产生幻读的情况。
- 读已提交:一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值。还是同样的例子,这次的事务隔离级别为读已提交的情况下,事务b不提交事务的情况下,事务a无法读到事务b更新后的数据,也就避免了脏数据产生。但是,当事务b提交之后,事务a再执行相同的数据,会发现数据变了,这就是所谓的不可重复读,意思就是同一个事务中多次执行相同的查询得到的结果不一致,同时,幻读的情况还是存在。
- 可重复读:一个事务第一次读过某条记录后,即使其他事务修改了该记录的值并且提交,该事务之后再读该条记录时,读到的仍是第一次读到的值,而不是每次都读到不同的数据,这就是可重复读,这种隔离级别解决了不可重复,但是还是会出现幻读。
- 串行化:这种隔离级别因为对同一条记录的操作都是串行的,所以不会出现脏读、幻读等现象,但是这也就不是并发事务了。
mysql的undo log
mvcc底层依赖mysql的undo log,undo log记录了数据库的操作,因为undo log是逻辑日志,可以理解为delete一条记录的时候,undo log会记录一条对应的insert记录,update一条记录的时候,undo log会记录一条相反的update记录,当事务失败需要回滚操作时,就可以通过读取undo log中相应的内容进行回滚,mvcc就利用到了undo log。
mvcc的实现原理
mvcc的实现,利用到了数据库的隐式字段,undo log和readview。首先来看隐式字段,其实mysql在表中的每行记录的后面,都隐式的记录了db_trx_id(最近修改(修改/插入)事务id),db_roll_ptr(回滚指针,指向这条记录的上一个版本),db_row_id(自增id,如果数据表没有主键,则默认以此id简历聚簇索引)这几个隐藏的字段。
undo log分为两种,分别为insert undo log,在insert新记录时产生的undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃,还有update undo log,事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除。mvcc利用到的是update undo log。
实际上undo log记录的是一个版本链,假设数据库中有一条记录如下:
现在有一个事务a修改了这条记录,把name改为tom,这个时候的操作流程为:
- 事务a首先对该行记录加上行锁
- 然后将该行记录拷贝到undo log中,作为一个旧的版本
- 拷贝完之后将该行name修改为tom,然后将该行的db_trx_id的值改为事务a的id,此时假设事务a的id为1,将该行的db_poll_ptr指向拷贝到undo log的那条记录
- 事务提交后,释放锁
此时的情况如下:
此时又有一个事务b来修改这条记录,把age改为28,这时候的操作流程为:
- 事务b对改行记录加上行锁
- 将该行记录拷贝到undo log中,作为一个旧的版本,此时发现undo log已经有记录了,那么新的一条undo log作为链表的表头插入到该行记录的undo log的最前面
- 拷贝完后将该行的age改为28,然后将该行的db_trx_id的值改为事务b的id,此时假设事务b的id为2,将该行的db_poll_ptr指向拷贝到undo log的那条记录
- 事务提交后释放锁
此时的情况如下:
从上面我们可以看到,不同的事务或者相同的事务对同一行记录进行的修改,会使得该行记录的undo log形成一个版本链,undo log的链首就是最近一次的旧记录,而链尾就是最早一次的旧记录。
现在我们来假设一种情况,先假设事务a和事务b都没有提交,这时候有一个事务c,修改了name为tom的记录,把age改成了30,然后把事务提交,事务c的id为3,同样的,会插入一条记录到undo log中,此时的undo log版本链链首记录的db_trx_id为3。
现在有一个事务d,查询name为tom的记录,此时将会启用快照读,快照是事务开始由查询操作触发的一个数据快照,不加锁的读在可重复读隔离级别下默认就是快照读,相对于快照读还有一个叫做当前读,更新操作都是当前读。在快照读时会产生一个读视图(read view),在该事务执行快照读的那一刻,会生成数据库当前的一个快照,记录并且维护当前活跃的事务的id,因为事务的id都是自增的,所以越新的事务id越大。读视图遵循可见性算法,而是否可见则需要做一些判断,读视图中除了记录当前活跃的事务id以外,还记录了当前创建的最大事务id,快照读时需要和read view做比较来获得可见性结果。
read view主要是把当前事务的id,和系统中的活跃事务的id作比较,比较的规则如下:
首先,read view中会有一个read view生成时刻系统中活跃的事务id的数组,暂称为id_list
然后read view中会记录一个id_list中最小的事务id,暂称为low_id
最后read view中还会记录一个read view生成时刻系统中尚未分配的事务id,也就是当前最大的事务id+1,暂称为high_id
- 当前事务id如果小于low_id,则当前事务可见
- 当前事务id如果大于high_id,则当前事务不可见
- 当前事务大于low_id小于high_id,再判断是否在id_list中,如果在,说明活跃的事务还没提交,当前事务不可见,但是对于活跃的事务本身可见,如果不在id_list中,则当前事务可见
如果可见性结果为不可见的话,需要通过db_roll_ptr到undo log中取出该记录的db_trx_id进行比较,通过遍历版本链,直到找到满足特定条件的db_trx_id, 那么这个db_trx_id所在的旧记录就是当前事务能看见的最新老版本。
以上就是mysql mvcc机制原理详解的详细内容,更多关于mysql mvcc机制原理的资料请关注开心学习网其它相关文章!
原文链接:https://juejin.cn/post/6950519591072170014
- mysql8.0.21的安装步骤(mysql8.0.23 msi安装超详细教程)
- mysql查看执行计划
- mysql怎么解决幻读问题(详解MySQL幻读及如何消除)
- mysql删除表内所有数据(mysql 大表批量删除大量数据的实现方法)
- 创建数据库入门教程mysql(MySQL数据库安装教程一学就会)
- 如何安装phpmysql环境(phpnow重新安装mysql数据库的方法)
- mysqldump导入导出(MySQL官方导出工具mysqlpump的使用)
- mysql 查询json(MySQL处理JSON常见函数的使用)
- mysql重新安装失败
- mysqlroot本地远程都可登陆(mysql5.7 设置远程访问的实现)
- mybatis为什么还用mysql(关于MyBatis连接MySql8.0版本的配置问题)
- 操作mysql的jdbc(JDBC连接的六步实例代码与mysql连接)
- mysql拼接和过滤(mysql 如何动态修改复制过滤器)
- mysql创建数据库教程(MySQL创建数据库并支持中文字符的操作方法)
- mysql全套优化(Mysql优化神器推荐)
- mysql 建表命令注释(mysql alter table命令修改表结构实例详解)
- 寒假余额不满24小时,不如来一场说走就走的亲子阅读之旅(寒假余额不满24小时)
- 省委书记出席的交流会,十位县委书记同场发言,代表公文材料的高水平(省委书记出席的交流会)
- 《刘老根3》热播,去世15年的她却再次被 伤害(去世15年的她却再次被)
- 十二星座爱情支配欲指数(十二星座爱情支配欲指数)
- 虐待儿童是发泄支配欲的愚蠢行为(虐待儿童是发泄支配欲的愚蠢行为)
- 你或许不知道你隐藏的支配欲望(你或许不知道你隐藏的支配欲望)
热门推荐
- anaconda如何配置python3.7(WIn10+Anaconda环境下安装PyTorch避坑指南)
- mysql8.0.26安装教程(mysql 8.0.22压缩包完整安装与配置教程图解亲测安装有效)
- python初学篇元组(元组列表字典莫烦python基础)
- 宝塔面板详细教程(使用宝塔面板建站时出现网页出现404错误怎么办?)
- laravel前后端分离实现排序(laravel自定义分页的实现案例offset和limit)
- javascript设置鼠标(JavaScript实现鼠标控制自由移动的窗口)
- web前端怎么设置图片的大小(Web前端绘制0.5像素的几种方法)
- php定时执行PHP(Cpanel下Cron Jobs定时执行PHP的方法)
- vue控制div滚动条(vue3实现CSS无限无缝滚动效果)
- java入坑rabbitmq(Python操作rabbitMQ的示例代码)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9