MySQL:MVCC原理详解

MySQL是允许多用户同时操作数据库的,那么就会出现多个事务的并发场景。那么再并发场景会出现很多问题:脏读、不可重复读、幻读的问题。

而解决这些问题所用到的方法就是:MVCC 多版本并发控制。而这个MVCC的实现是基于read_view、undoLog

如果不了解这几种问题的概念可以看这两篇博客:

MySQL:事务隔离级别详解MySQL:三大日志(binlog、redo log、undo log)

1、 reda_view

read view是一个数据库的内部快照,它记录了数据库在某个时刻 的数据信息。read view用于实现事务的隔离性,即在并发事务中,一个事务能看到哪些数据,以及哪些数据对其他事务不可见。read view的生成时机 和事务的隔离级别有关,例如,在可重复读 隔离级别下,read view会在事务开始时 生成,而在读已提交 隔离级别下,read view会在每条查询语句执行时生成。

除了记录着数据之外,它还记录着几个变量来辅助我们来判定可见性。

  • min_trx_id:在生成Read View时,当前系统中活跃的读写事务中最小的事务ID,即m_ids中的最小值;
  • max_trx_id:最后开始的事务,该SQL启动时,当前事务链表中最大的事务id编号,也就是最近创建的除自身以外最大事务编号。
  • m_ids:在生成Read View时,当前系统中活跃的读写事务的事务ID列表;
  • creator_trx_id:在生成Read View时,当前事务的事务ID。

reda_view的判断规则:

  • 如果事务id小于min_trx_id,表示该事务在read view生成之前已经提交,所以对当前事务可见。
  • 如果事务id大于max_trx_id,表示该事务在read view生成之后才开始,所以对当前事务不可见。
  • 如果事务id在min_trx_id和max_trx_id之间,那么需要查看该事务id是否在m_ids中。如果在,表示该事务在read view生成时仍在活跃,所以对当前事务不可见;如果不在,表示该事务在read view生成之前已经提交,所以对当前事务可见。

2、undo log

MVCC中判断可见性判断的就是下面这个undo log的版本链,假设要查询id为1的记录的姓名,此次事务id(trx_id)为63,那么版本链第一个看到事务id为66,假设此时创建的reda_view中的max_trx_id为65,那就说明名字为小吴的是再此次查询创建reda_view后才进行的修改,所以对此次的查询事务不可见。所以查询出来的应该是小王。

3、MVCC实现 可重复读 和 读已提交

上图再没有使用MVCC版本控制的时候,会出现上面这种问题,再一个事务中读取两次得到的结果不想同,这个就是不可重复读 的问题,那么MVCC是只会再第一次查询语句时生成read_View快照,

  1. 事务A第一次查询查出来很正常是"小王",
  2. 再第二次查询前事务B提交,将小王改为小吴。
  3. 然后事务A进行第二次查询,根据第一次查询时生成的read_View中,根本没有这条记录,则此条记录对A来说是不可见的,所以查询出来的还是小王。

如果是读已提交的隔离级别,则是**每执行一次查询语句都会生成reda _View,**这样也就能再第二次读的时候生成新的read_View ,然后看到版本链中改成小吴的这条undo log日志了。然后进行可见性判断,此时事务Bid>事务Aid,但又不在活跃事务列表中。说明生成此次快照时,事务B已经提交了,所以条记录对于事务A来说是可见的。

4、幻读的解决

  • 针对快照读(普通 select 语句),可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好了避免幻读问题。
  • 针对当前读 (select ... for update 等语句),是通过 next-key lock(记录锁+间隙锁)方式解决了幻读,因为当执行 select ... for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。
相关推荐
夜泉_ly2 小时前
MySQL -安装与初识
数据库·mysql
qq_529835353 小时前
对计算机中缓存的理解和使用Redis作为缓存
数据库·redis·缓存
月光水岸New5 小时前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
狄加山6755 小时前
数据库基础1
数据库
我爱松子鱼5 小时前
mysql之规则优化器RBO
数据库·mysql
chengooooooo6 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
Rverdoser6 小时前
【SQL】多表查询案例
数据库·sql
Galeoto7 小时前
how to export a table in sqlite, and import into another
数据库·sqlite
人间打气筒(Ada)7 小时前
MySQL主从架构
服务器·数据库·mysql
leegong231117 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql