[mysql 学习笔记] - 多版本并发控制 MVCC

MVCC 定义

MVCC(Multi-Version Concurrency Control)多版本并发控制,它是一种并发控制的方法。

MVCC 会保存某个时间点上的数据快照,这意味着同一个事务在执行过程中,始终可以看到一个一致的数据视图。这同时也意味着不同的事务在同一个时间点看到的同一个表的数据可能是不同的。

不同的存储引擎,实现 MVCC 的方法也不一样。

-- 百科 MVCC

一致性非锁定读、锁定读

一致性非锁定读

一致性非锁定读(Consistent Nonlocking Reads)也叫 快照读,普通的 SELECT 语句就是执行的快照读。

InnoDB 使用 多版本(multi versioning)技术读取数据库在某个时刻的快照,它能查询到其他事务在该时刻之前已经提交的数据。当然,如果是本事务的修改都是可读取的。

锁定读

锁定读(Locking Reads)也叫当前读。SELECT ... FOR UPDATE、SELECT ... LOCK IN SHARE MODE 都属于当前读,通过对记录加锁来实现。

InnoDB 中 MVCC 的实现

InnoDB 通过保存数据行的历史版本来实现 MVCC,这些历史版本数据保存在回滚段中(undo 日志)。

具体实现涉及到相关概念:隐藏列、Read View

隐藏列

InnoDB 会为每一个数据行添加 三个隐藏列:

  • DB_TRX_ID
    6 byte,最近修改(修改/插入)的事务ID;删除也被视为修改,只是通过一个特殊标记位来表示已删除;
  • DB_ROLL_PTR
    7 byte,回滚指针,指向这条记录的上一个版本(存储于 rollback segment 里)
  • DB_ROW_ID
    6 byte,自增ID(隐藏主键),如果数据表没有主键,也不存在唯一索引,InnoDB 会以 DB_ROW_ID 作为聚簇索引列。

假设表 custInfo 包含一条记录,它的存储如下(忽略自增 ID):

此时事务 T1 对年龄进行修改,假设事务 ID 为 1;

InnoDB 会把该数据行拷贝一份到 undo log 中,然后修改当前记录的 age 值,同时将 DB_TRX_ID 设置为当前事务 ID,DB_ROLL_PTR 指向先前拷贝到 undo log 日志的副本记录:

 如果此时又有一个事务 T2 对年龄进行修改,假设事务 ID 为 2,执行和 T1修改时一样,将会形成如下链表:

 可以看到,InnoDB 使用 DB_TRX_ID DB_ROLL_PTR 这两个隐藏列以及 undo 日志形成了一个数据版本链。

Read View

Read View 是某一事务 执行快照读时产生的 当前所有活跃事务的一个视图,用作可见性判断。

Read View 有四个重要字段:

  • m_ids:生成 Read View 时,当前系统中 尚未提交的 事务 id 列表
  • min_trx_id:生成 Read View 时,当前系统中 尚未提交的事务列表中最小的事务 id,即 m_ids 中的最小值;
  • max_trx_id:生成 Read View 时,系统中 应该分配给下一个事务的 id 值;即 m_ids 中的最大值 + 1;
  • creator_trx_id:创建该 Read View 的事务 id。

可见性规则

结合上一节描述的版本链,Read View 遵循以下可见性规则:

1、如果被访问的记录版本号 DB_TRX_ID 等于 Read View 中的 creator_trx_id ,表明当前事务访问的是自己修改的记录,可以被访问;

2、如果被访问的记录版本号 DB_TRX_ID 小于 min_trx_id,表明该版本的数据在当前事务生成 Read View 之前已经提交,可以被访问;

3、如果被访问的记录版本号 DB_TRX_ID 大于或等于 max_trx_id值,表明生成该版本数据的事务在当前事务生成 Read View 后才开启,不可以被访问,需要沿着回滚指针寻找该记录的历史版本继续判断;

4、如果被访问的记录版本号 DB_TRX_ID 介于 min_trx_id 和 max_trx_id 之间,需要进一步判断 DB_TRX_ID 是不是在活跃事务列表 m_ids 中:

  • 如果在:说明创建 Read View 时生成该版本的事务尚未提交,该版本数据不可以被访问,需要沿着回滚指针寻找该记录的历史版本继续判断;
  • 如果不在:说明创建 Read View 时生成该版本的事务已经被提交,可以被访问,直接返回。

相关知识

脏读、不可重复读、幻读

当数据库上有多个事务同时进行操作时,就可能会出现 脏读、不可重复读、幻读 等问题:

脏读

一个事务读到了 别的事务修改但尚未提交的数据

比如事务 T1 执行过程中修改了数据 X,在未提交前,事务 T2 读取了X,而事务 T1 之后发生回滚,这样事务 T2 就形成了脏读;

不可重复读

一个事务 多次读取同一数据,但是多次读取的结果不一致。

比如事务 T1 首先读取客户 A 的年龄为 20 ,此时,另一个事务 T2 将客户 A 的年龄修改为 21,并且提交,然后,事务 A 又重新读取一次客户 A 的年龄变成了 21,和上一次的不一样,即先后多次读取的结果不一致;

幻读

一个事务多次执行同样的读取操作,读到的 结果集不一致

不可重复读强调的是同一数据行字段值发生变更,幻读强调的是结果集的记录条数发生变更。

事务隔离级别

通过设置不同的事务隔离级别可以解决相应的问题:

READ UNCOMMITTED 未提交读:

即使一个事务没有提交,它的所有变更都可以被其他事务看到;

READ COMMITTED 已提交读:

一个事务只有在提交之后,它的变更才可以被其他事务看到;

REPEATABLE READ 可重复读:

一个事务在执行过程中,每次看到的结果都保持一致;

SERIALIZABLE 串行读:

序列化,强制事务排序,使之不会发生冲突。

不同隔离级别下,并发事务可能产生的问题

脏读不可重复读幻读
未提交读
已提交读
可重复读
串行化

READ COMMITTED 和 REPEATABLE READ 都是通过 MVCC 来实现的,它们的区别仅在于 生成 Read View 的时机不同

  • READ COMMITTED 在每次读取数据前都会生成一个 Read View;
  • REPEATABLE READ 仅在第一次读取时生成一个 Read View,以后的读取都使用这个 Read View。

InnoDB 解决 幻读

InnoDB 引擎的默认隔离级别是 REPEATABLE READ,它是通过 MVCC 来实现的,单从这个角度来看,它已经解决了幻读问题,因为它只在首次查询的时候生成快照,之后都使用这一快照。当然,需要看到的是 MVCC 讨论的是快照读,也就是我们普通的 SELECT 查询,而形如 SELECT ... FOR UPDATE、SELECT ... LOCK IN SHARE MODE,update,insert 等这类操作都属于当前读,当前读不再读取快照数据,它读的就是当前最新的记录,因此,如果没有其他手段就会出现幻读问题。

InnoDB 通过使用 next-key 锁 的方式解决了当前读可能出现的幻读问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
版本并发控制(MVCC)是MySQL中的一种技术,它通过维护数据的多个版本,以实现读写操作的并发控制MVCC通过在每行记录后面保存两个隐藏的列(一个保存行的创建时间,一个保存行的删除时间)来实现。当一个事务读取数据时,它会根据事务开始的时间戳和行的版本信息来确定可见的数据版本。这种机制在InnoDB存储引擎中被广泛使用,可以提供一致性读操作的保证。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [MySQL之InnoDB存储引擎-MVCC](https://blog.csdn.net/qq_53267860/article/details/125073612)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [MySQL数据库版本并发控制MVCC](https://blog.csdn.net/iuu77/article/details/129132863)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [mysql版本并发控制MVCC的实现](https://download.csdn.net/download/weixin_38607195/14907745)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值