MySQL MVCC 详解

MVCC 基本概念

当前读

读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select…lock in share mode【共享锁】,select…for update、update、insert、delete【排他锁】都是一种当前读。

快照读

简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。

Read Committed:每次select,都生成一个快照读。

Repeatable Read:开启事务后第一个 select 语句才是快照读的地方。

Serializable:快照读会退化为当前读。

演示当前读和快照读的区别:

在这里插入图片描述

MVCC

全称 【Multi-Version Concurrency Control】,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为 MySQL 实现 MVCC 提供了一个非阻塞读功能、一种无锁的实现方式。

MVCC 的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log日志、readView

MVCC 实现原理

隐藏字段

MySQL 中的行数据,除了我们肉眼能看到的字段之外,其实还包含了一些隐藏字段,它们在内部使用,默认情况下不会显示给用户。如下图除了 id、age、name 用户创建的字段,还有 DB_TRX_ID、DB_ROLL_PTR

在这里插入图片描述

字段含义
DB_TRX_ID最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID。
DB_ROLL_PTR回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本。
DB_ROW_ID隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。

undo log 日志

undo 日志(Undo Log)是 MySQL 中的一种重要的事务日志,undo 日志的作用主要有两个方面:

  • 事务回滚:记录数据在执行之前是什么样子的,在 insert、update、delete 的时候产生的便于数据回滚的日志。
  • MVCC 实现:MVCC 是 InnoDB 存储引擎的核心特性之一。通过使用 undo 日志,MySQL 可以为每个事务提供独立的事务视图,使得事务读取数据时能看到一致且符合隔离级别要求的数据版本。

undo log 的版本链

不同事务或相同事务对同一条记录进行修改,会导致该记录的 undo log 生成一条记录版本链表,链表的头部是最新的旧记录,链表的尾部是最早的旧记录,回滚指针指向最近的一次的修改记录。

如下图:

事务 2 将 age 改为 3,修改该行数据时,数据库会先对该行加排他锁,然后把该行数据拷贝到 undo log 中作为旧记录,即在 undo log 中有当前行的拷贝副本,当拷贝完成后,隐藏字段中的 BD_TRX_ID 会自增,DB_ROLL_PTR 回滚指针指向 undo log 的副本记录,即表示我的上一个版本就是它,事务提交后,释放锁。

事务 3、4 同理,指向上一个版本,此时就形成了一条版本链。

在这里插入图片描述

具体流程如下:

  1. 在更新或删除操作之前,MySQL 会将旧值写入 undo log 中。
  2. 当事务需要回滚时,MySQL 会根据事务的 undo log 记录,通过 DB_ROLL_PTR 找到对应的 undo log。
  3. 根据 undo log 中记录的旧值,MySQL 将旧值恢复到相应的数据行中,实现数据的回滚操作。

ReadView

ReadView(读视图)是快照读 SQL 执行时 MVCC 提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。

ReadView 中包含了四个核心字段:

字段含义
m_ids当前活跃的事务ID集合(或者叫未提交的事务ID)
min_trx_id最小活跃事务ID(在m_ids找个最小的)
max_trx_id预分配事务ID,就是当前最大事务ID+1(因为事务ID是自增的)
creator_trx_idReadView 创建者的事务ID

其中版本链数据访问规则为:

在这里插入图片描述

不同的隔离级别,生成 ReadView 的时机不同:

READ COMMITTED:在事务中每一次执行快照读时生成ReadVieW。

REPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该 ReadView,所以才叫可以重复读。

为方便大家记忆我画了一张图:

绿色:可见
红色:不可见
在这里插入图片描述

RC 隔离级别下的 MVCC

在这里插入图片描述

以第一次查询为例:

trx_id(当前事务ID):4 -> 3 -> 2 -> 1

m_ids(当前活跃的事务ID集合):{3,4,5}

min_trx_id(最小活跃事务ID):3

max_trx_id(预分配事务ID,当前最大事务ID+1):6

creator_trx_id(ReadView创建者的事务ID):5

从条件一至到条件四,trx_id一直从 4 -> 3 -> 2 -> 1,只要有规则成立的就返回当条记录

在图上例子中,当 trx_id 等于 2 的时候,trx_id < min_trx_id 成立了,所以就返回该条记录

RR 隔离级别下的 MVCC

在 RC 隔离级别,同一个事务中读取两次相同的记录是一样的,因为在第一次读取数据时生成一个 ReadView,后面会复用第一次生成的,所以才叫可重复读。

在这里插入图片描述

MVCC解决了什么问题

  1. 脏读:在没有MVCC的情况下,一个事务可能读取到另一个未提交事务修改过的数据,如果后者回滚,那么前者读取的就是“脏”数据。MVCC通过确保事务只能读取到已提交的数据版本,从而避免了脏读问题。

  2. 不可重复读:在数据库操作期间,如果没有适当的隔离机制,一个事务多次读取同一数据可能会得到不同的结果,因为其他事务可能在此期间修改了这些数据。MVCC通过为每个事务提供一个一致的数据快照,使得在同一个事务中的多次读取操作能够得到相同的结果,从而解决了不可重复读问题。

  3. 幻读:幻读是指在同一个事务中,执行相同的查询语句,但第二次查询却返回了第一次查询中没有的新记录。虽然MVCC并不能完全解决幻读问题,但它可以在一定程度上减少幻读的发生,尤其是在读取时没有主动加锁的情况下。在某些数据库系统中,如MySQL的InnoDB存储引擎,幻读问题可以通过使用间隙锁来进一步解决。

  4. 提高并发性能:MVCC允许读写操作同时进行,读操作不需要等待写操作完成,写操作也不会阻塞读操作。这种并发控制方式显著提高了数据库的并发处理能力,尤其是在读多写少的场景下。

  5. 减少锁的使用:虽然MVCC本身也是一种形式的锁定机制,但它减少了传统意义上的行锁或表锁的需求。通过维护多个数据版本,MVCC能够在不加锁的情况下实现数据的并发访问,从而减少了锁竞争和锁开销。

  6. 避免数据丢失:在写写操作中,如果没有合适的并发控制机制,可能会导致数据丢失问题。MVCC通过确保每个写操作都在其自己的数据版本上进行,从而避免了数据丢失问题

### 回答1: MySQLMVCC(Multi-Version Concurrency Control)机制是通过为每个读操作创建一个版本(Version)并保留旧版本来实现的。这个机制允许多个事务同时访问同一数据行,同时确保它们不会互相干扰或产生冲突。 MVCC在MySQL的实现方式是,对于每一行数据,在表存储一个隐藏的系统版本号(system versioning),并将每个操作(包括SELECT查询)的时间戳与该行的版本号进行比较。当读取一行数据时,MySQL会根据当前的事务时间戳和行的版本号来决定该行是否可见。如果行的版本号早于当前事务的时间戳,则说明该行是旧版本,不可见;如果行的版本号晚于当前事务的时间戳,则说明该行是新版本,可见。 在MVCC机制下,读操作不会阻塞写操作,写操作也不会阻塞读操作。因此,MVCC机制可以提高并发性能和可伸缩性,使得多个事务可以同时访问同一数据库而不会产生锁定和阻塞问题。 但是,MVCC机制也有一些限制。例如,如果事务A在读取某个数据行的同时,事务B修改了该行的值,那么事务A在提交时就会检测到该数据行已经被修改,从而回滚该操作。此外,MVCC机制也会占用更多的存储空间来存储旧版本的数据行。 ### 回答2: MySQLMVCC(多版本并发控制)是一种用于处理并发访问的机制。MVCC是通过在数据库的各种操作(如事务的开启、读取和写入)使用隐藏的时间戳来实现的。 MVCC的主要目标是避免读取和写入操作之间的冲突,从而提高数据库的并发性能和资源利用率。它通过在内部为每个事务提供一个唯一的时间戳来实现。每个事务在开始时都会获得一个时间戳,并且事务的每个操作都使用这个时间戳。 当一个事务读取数据时,它只能读取它开始时间之前的数据版本。这样可以避免读取到其他事务正在写入或修改的数据,从而保证读取操作的一致性和隔离性。 当一个事务写入数据时,它会创建一个新的数据版本,并将其与事务的时间戳关联。这个新版本的数据不会立即覆盖旧的数据,而是以一种类似于快照的方式存在。其他事务在读取数据时仍然可以访问旧版本的数据。 MVCC还使用了回滚段(undo log)来处理事务的回滚操作。当一个事务被回滚时,数据库会使用回滚段将所有该事务做出的修改逆转回去,从而恢复到事务开始之前的状态。 需要注意的是,MVCC机制对于并发性能和资源利用率的提升是有限的。在高并发的情况下,数据库可能会出现锁等待和资源竞争的问题。为了进一步优化并发性能,可以考虑使用其他技术,如乐观并发控制(Optimistic Concurrency Control)和分布式数据库。 ### 回答3: MySQLMVCC(Multi-Version Concurrency Control)机制是一种并发控制技术,用于处理数据库的读写冲突。它允许多个事务同时读取数据库,同时也使得读写冲突被有效地解决。 MVCC机制基于以下两个重要的概念:版本号和快照。 首先,每个表的每个行都有一个版本号。当一个事务对某行进行修改时,会为该事务创建一个新的版本,并将旧版本标记为过期。这样,读取该行的事务会读取到未过期的版本,而不会受到写用户的影响。同时,这也避免了仅读用户被阻塞的情况。 其次,为了实现读取未过期版本的行,MVCC机制通过创建快照来实现。快照是数据库在某个时间点的一个镜像,其包含了未过期的行版本。当一个读取事务开始时,会生成一个当前的数据库快照,并基于这个快照来读取数据行。这样,读取事务不会看到在其开始时(即快照生成时)已提交的写入事务,从而实现了读写并发。 MVCC机制对于提高数据库的并发性能非常重要。它允许多个事务同时进行读操作,提高了数据库的并发处理能力。此外,它也避免了读写冲突和阻塞的情况,提高了数据库的效率和稳定性。 总之,MySQLMVCC机制通过使用版本号和快照来实现读写并发控制和冲突的解决。它是提高数据库并发性能和减少阻塞的关键技术之一,并且在实际的数据库应用扮演着非常重要的角色。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tiantian17)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值