MVCC-多版本并发控制

目录

[什么是MVCC ?](#什么是MVCC ?)

MVCC关键知识点

隐式字段

事务ID

[undo log](#undo log)

版本链

快照和当前读

[Read View](#Read View)

MVCC实现原理

执行流程

MVCC实现"读已提交"


什么是MVCC ?

MVCC(Mutil-Version Concurrency Control),全称:多版本并发控制 ,这是一种并发事务环境下实现数据安全控制的方法 ,其本质上是一种乐观锁 的实现。MySQL在InnoDB存储引擎中,通过MVCC实现读已提交 (READ COMMITTD)和可重复读(REPEATABLE READ)这两种隔离级别。相对于加锁,MVCC用更好的方式去处理读写冲突,有效提高数据库并发性能。

MVCC关键知识点

MVCC的实现,主要通过事务IDundolog 日志版本链

隐式字段

InnoDB存储引擎,每一行记录都有两个隐藏列trx_id、roll_pointer,如果表中没有主键和非NULL唯一键时,则还会有第三个隐藏的主键列row_id。

事务ID

事务每次开启前,都会从数据库获得一个事务ID:trx_id,该值属于自增长,每进行一次事务操作,就会自增1。可以从事务ID判断事务的执行先后顺序。

undo log

undo log,回滚日志,用于记录数据被修改前的信息。在表记录修改之前,会先把数据拷贝到undo log里,如果事务回滚,即可以通过undo log来还原数据。也可以用于用于MVCC快照读。

版本链

多个事务并行操作某一行数据时,不同事务对该行数据的修改会产生多个版本,然后通过回滚指针(roll_pointer),连成一个链表,这个链表就称为版本链。

假设现在有一张core_user表,表里面有一条数据,id为1,名字为孙权:

现在开启一个事务A:对core_user表执行update core_user set name ="曹操" where id=1,会进行如下流程操作

  • 首先获得一个事务ID=100
  • 把core_user表修改前的数据,拷贝到undo log
  • 修改core_user表中,id=1的数据,名字改为曹操
  • 把修改后的数据事务Id=101改成当前事务版本号,并把roll_pointer指向undo log数据地址。

快照和当前读

快照读

读取的是记录数据的可见版本(有旧的版本)。不加锁,普通的select语句都是快照读。

例如:

select * from core_user where id > 2;

当前读

读取的是记录数据的最新版本,显式加锁的都是当前读。

例如:

select * from core_user where id > 2 for update;

select * from account where id > 2 lock in share mode;

Read View

事务在执行SQL时,会产生一个ReadView数据快照,用于判断当前事务可见哪个版本的数据

ReadView中保存了四个重要字段:

  • m_ids:通过一个List数据结构,保存未提交的活跃读写事务ID。
  • min_limit_id:表示生成Read View时,活跃读写事务中最小的事务id,即m_ids中的最小值。
  • max_limit_id:表示生成Read View时,系统中应该分配给下一个事务的id值。
  • creator_trx_id: 创建当前Read View的事务ID。

可见性判断规则:

当事务查询数据时,会从版本链的最新版本开始,通过 Read View 判断该版本是否可见。若不可见,则沿DB_ROLL_PTR回溯到上一个版本,重复判断,直到找到可见版本或版本链结束(返回空)。

对于版本链中的某个版本( DB_TRX_ID 为trx_id),当前事务能否看到它,取决于:

  • 若trx_id == creator_trx_id:该版本由当前事务修改,可见;
  • 若trx_id < min_trx_id:修改该版本的事务在当前事务生成 Read View 前已提交,可见;
  • 若trx_id > max_trx_id:修改该版本的事务在当前事务生成Read View 后才启动,不可见;
  • 若min_trx_id ≤ trx_id ≤ max_trx_id:

若trx_id在m_ids中(即修改事务仍活跃),不可见;

若trx_id不在m_ids中(即修改事务已提交),可见。

MVCC实现原理

执行流程

  1. 获取事务的版本号,即事务ID
  2. 获取Read View
  3. 查询得到的数据,然后Read View中的事务版本号进行比较。
  4. 如果不符合Read View的可见性规则, 即就需要Undo log中历史快照;
  5. 最后返回符合规则的数据

所以,InnoDB 实现MVCC,是通过Read View+ Undo Log实现的,Undo Log 保存了历史快照,Read View可见性规则帮助判断当前版本的数据是否可见。

MVCC实现"读已提交"

在读已提交的事务隔离级别下,仍然存在不可重复读的事务并发问题。

例如:core_user表中,已存在如下数据,事务隔离级别设置为读已提交(RC),事务A和事务B同时对core_user表进行查询和修改操作。

最终,事务A查询到的结果是,name=曹操的记录,发生不可重复读的事务并发问题。

MVCC的执行流程如下:

  1. A开启事务,首先得到一个事务ID为100:trx_id=100
  2. B开启事务,得到事务ID为101:trx_id=101
  3. 事务A和事务B,会各自生成一个Read View
  4. 事务A第一次查询时,通过trx_id=100,查到name=孙权
  5. 事务B进行修改操作,把名字改为曹操。把原数据拷贝到undo log,然后对数据进行修改,标记事务ID和上一个数据版本在undo log的地址。
  6. 事务A再次执行查询操作,会新生成一个Read View
  7. 回到版本链中,查找到最新版本的列name的内容是:曹操该版本的trx_id值为101
相关推荐
Hx__3 小时前
MySQL InnoDB 的 MVCC 机制
数据库·mysql
速易达网络3 小时前
ASP.NET MVC 连接 MySQL 数据库查询示例
数据库·asp.net·mvc
玉衡子3 小时前
MySQL基础架构全面解析
数据库·后端
梦中的天之酒壶3 小时前
Redis Stack扩展功能
数据库·redis·bootstrap
GreatSQL3 小时前
GreatSQL分页查询优化案例实战
数据库
Leo.yuan4 小时前
不同数据仓库模型有什么不同?企业如何选择适合的数据仓库模型?
大数据·数据库·数据仓库·信息可视化·spark
麦兜*4 小时前
MongoDB 6.0 新特性解读:时间序列集合与加密查询
数据库·spring boot·mongodb·spring·spring cloud·系统架构
chat2tomorrow4 小时前
数据采集平台的起源与演进:从ETL到数据复制
大数据·数据库·数据仓库·mysql·低代码·postgresql·etl
稻草人想看远方4 小时前
关系型数据库和非关系型数据库
数据库