Mysql的MVCC机制

MVCC

Multi Version Concurrency Control的简称,代表多版本并发控制,实现非锁定一致性读

概念:

非锁定读 快照读(查询的行执行删除或修改操作,则读取快照数据,(历史数据),)多版本控制??锁定读 ???select ... lock in share mode:对记录加 S 锁,其它事务也可以加S锁,如果加 x 锁则会被阻塞? S锁和X锁??? Read View :判断可见性,即其他事务对当前事务是否可见。 Next-key-Lock???
purge 操作:通过 undo log 读取之前的版本数据,以此实现非锁定读,对同一个数据行的修改,最终undo log记录会形成一个链表,表头就是最新版本记录(ReadView+可读性算法分析时就是根据这个链表所记录的事务id 和 当前事务的id进行比较从而确认读取哪个历史记录)

一致性非锁定读&&锁定读

一致性非锁定读:

通常的做法是: 在每一行记录添加一个隐藏的版本号或时间戳,更新时该行的版本号+1(或时间戳改变),读取时,当前可见的版本号对应记录的版本号进行比对,如果记录的版本小于可见版本,则表示该记录可见。
在RC和RR两个隔离级别的情况下,select(不包括 select ... lock in share mode ,select ... for update)会默认使用MVCC机制。

锁定读:锁定读的语句:
  • insert、update、delete 操作
  • select ... for update 、select ... lock in share mode

InnoDB对MVCC的实现:

MVCC 的实现依赖于:隐藏字段、Read View、undo log。隐藏字段中的DB_TRX_ID和ReadView实现当前数据是否对事务可见,如不可见,则通过数据行的 DB_ROLL_PTR 找到 undo log 中的历史版本。

隐藏字段:
DB_TRX_ID: 表示最后一次插入或更新该行的事务 id。此外,delete 操作在内部被视为更新,只不过会在记录头 Record header 中的 deleted_flag 字段将其标记为已删除DB_ROLL_PTR: 回滚指针,指向undo logDB_ROW_ID: 如果没有主键和唯一非空索引时会自动创建,并使用该id生成聚簇索引

Read View结构:

class ReadView {
  /* ... */
private:
  trx_id_t m_low_limit_id;      /* 如果行记录大于等于这个 ID,
  则 当前事务不可读取这个行号的数据,   值当前事务id+1 */

  trx_id_t m_up_limit_id;       /* 如果行上的DB_TRX_ID小于这个值,则当前事务可读取这个行,
  活跃列表中的最小id,如果活跃列表为空则等于 m_low_limit_id */

  trx_id_t m_creator_trx_id;    /* 创建该 Read View 的事务ID */

  trx_id_t m_low_limit_no;      /* 事务 Number, 小于该 Number 的 Undo Logs 均可以被 Purge */

  ids_t m_ids;                  /* 创建 Read View 时的活跃事务列表,当前未提交事务 ID 集合,
  后续即使这些id里的事务修改了数据,对当前事务时不可见的*/

  m_closed;                     /* 标记 Read View 是否 close */
}

undo log

用于事务回滚时恢复数据。当读取记录时,若该记录被其他事务占用或当前版本对该事务不可见,则可以通过 undo log 读取之前的版本数据,以此实现非锁定读。
undo log类型

  • insert undo log :
    指在 insert 操作中产生的 undo log。因为 insert 操作的记录只对事务本身可见,对其他事务不可见,故该 undo log 可以在事务提交后直接删除。不需要进行 purge 操作
  • update undo log:
    update 或 delete 操作中产生的 undo log。该 undo log可能需要提供 MVCC 机制,因此不能在事务提交时就进行删除。提交时放入 undo log 链表,等待 purge线程 进行最后的删除.

RR和RC两个隔离级别下的MVCC实现差距

在事务隔离级别 RC 和 RR (InnoDB 存储引擎的默认事务隔离级别)下,InnoDB 存储引擎使用 MVCC(非锁定一致性读),但它们生成 Read View 的时机却不同在 **RC 隔离级别下的 每次select **查询前都生成一个Read View **(m_ids 列表)在 ==RR 隔离级别下只在事务开始后 第一次select ==数据前生成一个Read View(m_ids 列表)

MVCC+Next-key-Lock 防止幻读

1、执行普通 select,此时会以 MVCC 快照读的方式读取数据在快照读的情况下,RR 隔离级别只会在事务开启后的第一次查询生成 Read View ,并使用至事务提交。所以在生成 Read View 之后其它事务所做的更新、插入记录版本对当前事务并不可见,实现了可重复读和防止快照读下的 “幻读”
2、执行 select...for update/lock in share mode、insert、update、delete 等当前读在当前读下,读取的都是最新的数据,如果其它事务有插入新的记录,并且刚好在当前事务查询范围内,就会产生幻读 !InnoDB 使用 Next-key Lock 来防止这种情况。当执行当前读时,会锁定读取到的记录的同时,锁定它们的间隙,防止其它事务在查询范围内插入数据。

posted @   habc706  阅读(90)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示