首页电脑使用mysql 多版本共存 mysql 多版本并发控制

mysql 多版本共存 mysql 多版本并发控制

圆圆2025-09-11 14:01:34次浏览条评论
MVCC通过维护数据多版本和读视图机制,在InnoDB中实现非阻塞读,提升并发性能。它利用undo log存储历史版本,结合事务ID和回滚指针判断数据可见性,避免脏读与不可重复读。该机制在READ COMMITTED和REPEATABLE READ隔离级别下发挥作用,减少读写冲突,而在READ UNCOMMITTED中被绕过,SERIALIZABLE中被锁机制替代。

mvcc(多版本并发控制)在mysql中是如何工作的?

MVCC在MySQL中,尤其是在InnoDB存储引擎里,本质上是一种非阻塞的读操作机制。它通过维护同一行数据的多个版本,让读操作可以读取到事务开始时的数据快照,而写操作则可以同时进行,互不干扰。这样一来,就极大地提升了数据库的并发性能,减少了读写之间的锁竞争,让用户体验到更流畅的数据访问。说白了,它让数据库在处理大量并发请求时,能像一个高效的多任务处理者,而不是一个排队等候的单线程程序。

解决方案

要理解MVCC是如何在MySQL中工作的,我们需要深入到InnoDB的一些核心机制。在我看来,这套设计精妙而实用。

当一个事务对某行数据进行修改(UPDATE或DELETE)时,InnoDB并不会直接覆盖或删除原始数据。相反,它会做几件事:

创建新版本: 它会为被修改的行创建一个新的版本。这个新版本包含了修改后的数据。记录事务ID: 每个行版本都会关联一个隐藏的事务ID(
DB_TRX_ID
登录后复制登录后复制登录后复制登录后复制),记录了是哪个事务创建或最后修改了它。指向旧版本: 另一个隐藏列是回滚指针(
DB_ROLL_PTR
登录后复制登录后复制登录后复制)。这个指针指向了
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制中的一个记录,该记录存储了当前行版本修改前的旧数据。通过这个指针,我们可以沿着链条追溯到这行数据的所有历史版本。Undo Log: 这就是关键了。
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制不仅用于事务回滚,更是MVCC实现多版本并发控制的核心。每当数据被修改,旧的数据值就会被写入
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制。这样,即使数据被更新了,其他事务仍然可以通过
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制找到并读取到它们需要看到的旧版本数据。

当一个

SELECT
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制语句(在特定的隔离级别下)被执行时,它会获得一个“读视图”(Read View),这可以理解为数据库在那个时间点的一个“快照”。这个读视图包含了当前所有活跃的事务ID列表。然后,InnoDB会根据以下规则来判断哪个行版本对当前的
SELECT
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制事务是可见的:

如果一个行版本的
DB_TRX_ID
登录后复制登录后复制登录后复制登录后复制小于读视图中最早的活跃事务ID,这意味着这个版本是在读视图创建之前就已经提交的,所以它是可见的。如果一个行版本的
DB_TRX_ID
登录后复制登录后复制登录后复制登录后复制大于读视图中最大的活跃事务ID,那么这个版本是在读视图创建之后才启动的事务修改的,所以它是不可见的。如果一个行版本的
DB_TRX_ID
登录后复制登录后复制登录后复制登录后复制在读视图的活跃事务ID列表中,那么这个版本是由一个尚未提交的事务修改的,同样不可见(除非是当前事务自己修改的)。如果当前版本不可见,InnoDB就会沿着
DB_ROLL_PTR
登录后复制登录后复制登录后复制指向的
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制链条,不断回溯,直到找到一个对当前读视图可见的旧版本。

通过这种机制,读事务总能看到一个一致的数据快照,而写事务则可以自由地修改数据,两者之间几乎没有阻塞,极大地提升了数据库的并发处理能力。

MVCC解决了哪些并发问题,与传统锁机制有何不同?

MVCC的引入,在我看来,是数据库并发控制领域的一个里程碑,它巧妙地解决了传统锁机制下的一些痛点。

MVCC解决的并发问题主要包括:

脏读(Dirty Reads)的避免: 在
READ COMMITTED
登录后复制登录后复制登录后复制和
REPEATABLE READ
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制隔离级别下,MVCC确保读事务不会看到其他未提交事务的修改。它总是提供已提交的数据版本,或者在
REPEATABLE READ
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制下提供事务开始时的那个一致快照。不可重复读(Non-Repeatable Reads)的缓解: 尤其是在MySQL默认的
REPEATABLE READ
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制隔离级别下,MVCC通过固定事务的读视图,保证了在一个事务的生命周期内,多次读取同一行数据会得到相同的结果,即便这期间有其他事务修改并提交了该行数据。读写冲突的减少: 这是MVCC最显著的优势之一。传统的锁机制下,读操作(共享锁)和写操作(排他锁)会互相阻塞。而MVCC允许读事务在不加锁的情况下读取数据的旧版本,写事务则只对当前写入的行加排他锁。这样,读写操作可以并行进行,极大地提高了并发度。幻读(Phantom Reads)的间接处理: 虽然MVCC本身并不能完全阻止幻读(因为幻读涉及的是行的增删,而非修改),但在
REPEATABLE READ
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制级别下,MySQL结合了间隙锁(Gap Locks)和Next-Key Locks来进一步解决幻读问题。不过,单就MVCC而言,它主要关注的是已有行的版本一致性。

与传统锁机制的不同:

阻塞性: 传统锁机制是“悲观锁”的典型代表,读写操作都会因为锁而互相阻塞,导致并发性能下降。MVCC则是一种“乐观”的并发控制策略,它允许读操作非阻塞地进行,只有在写操作时才需要对具体行加锁。数据可见性: 锁机制下,读事务只能看到当前已提交的最新数据(如果未被其他事务锁定)。MVCC则能让读事务看到其事务开始时的数据快照,即使之后有新的提交,它也坚持看自己的“旧”版本。实现复杂性: MVCC的实现比纯粹的锁机制要复杂,因为它需要维护多版本数据(通过undo log),并管理读视图和版本可见性规则。但这种复杂性带来的回报是更高的并发性能。资源开销: MVCC需要额外的存储空间来保存旧版本数据(undo log),并且需要CPU开销来遍历undo log链条以找到合适的版本。锁机制也有锁管理和死锁检测的开销。两者各有侧重。

在我看来,MVCC的出现,让数据库的并发控制从“排队等候”的模式,转向了“各取所需”的模式,这无疑是其魅力所在。

Remover Remover

几秒钟去除图中不需要的元素

Remover115 查看详情 Remover MVCC的实现细节中,Undo Log扮演了什么角色?

在MVCC的舞台上,

undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制绝对是一个不可或缺的幕后英雄,它的作用远不止我们字面上理解的“撤销”那么简单。我个人认为,没有
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制,MVCC的诸多精妙设计都将无从谈起。

Undo Log在MVCC中的核心角色包括:

版本数据的存储库: 这是
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制最直接也是最重要的功能。每当InnoDB中的一行数据被修改(
UPDATE
登录后复制或
DELETE
登录后复制),原始数据(修改前的值)并不会立即被丢弃,而是会被记录到
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制中。这些被记录下来的旧数据,就构成了行数据的“历史版本”。当一个事务需要读取某个行数据,但当前最新的版本对它不可见时(比如,最新版本是由一个尚未提交的事务修改的,或者是在当前事务启动之后才提交的),数据库就会沿着
DB_ROLL_PTR
登录后复制登录后复制登录后复制(回滚指针)指向的
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制链条,回溯到
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制中存储的旧版本,直到找到一个对当前事务的读视图可见的版本。事务回滚的基石: 当然,
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制的本职工作——提供事务回滚的能力——在MVCC中也同样重要。如果一个事务执行到一半需要撤销所有操作(
ROLLBACK
登录后复制),数据库就会利用
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制中记录的信息,将所有修改过的数据恢复到事务开始前的状态。这保证了事务的原子性。提供一致性读(Consistent Read):
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制是实现MVCC“一致性读”的关键。一致性读意味着一个事务在读取数据时,会看到一个在它事务开始时就已经存在的数据快照,即使其他事务在这期间修改了数据并提交了。如果当前数据版本不符合这个快照要求,
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制就提供了追溯历史版本的能力,让读事务总能看到符合其隔离级别和读视图要求的数据。数据清理(Purge)的依据:
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制记录的数据并不会永久保存。当一个
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制记录不再被任何活跃事务引用(即,没有事务需要读取这个旧版本,也没有事务需要回滚到这个状态),它就可以被清除以回收空间。这个清理过程通常由一个后台的
Purge
登录后复制线程完成。
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制的存在,为数据库判断何时可以安全地删除旧版本数据提供了明确的依据。

可以说,

undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制就像一个时光机,它存储了数据的“过去”,让不同的事务可以根据自己的时间线去查看相应的数据版本。这使得读写操作能够和谐共存,是InnoDB高并发性能的秘密武器之一。

在MySQL中,哪些隔离级别受益于MVCC,又有哪些不适用?

隔离级别和MVCC的关系,在我看来,是理解MySQL并发控制不可或缺的一环。MVCC并不是对所有隔离级别都“一视同仁”的,它的作用和效果会因隔离级别的不同而有显著差异。

主要受益于MVCC的隔离级别:

READ COMMITTED (RC): 这个隔离级别是MVCC的典型应用场景之一。在
READ COMMITTED
登录后复制登录后复制登录后复制级别下,一个事务的每次
SELECT
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制查询都会创建一个新的读视图(snapshot)。这意味着,如果其他事务在两次
SELECT
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制查询之间提交了数据修改,当前事务的第二次
SELECT
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制可能会看到这些新的提交。MVCC在这里的作用是,它确保了任何
SELECT
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制查询都只能看到已提交的数据,避免了“脏读”。但由于每次
SELECT
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制都有新的读视图,它无法避免“不可重复读”。REPEATABLE READ (RR): 这是MySQL InnoDB的默认隔离级别,也是MVCC发挥最大作用的隔离级别。在
REPEATABLE READ
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制级别下,一个事务的读视图是在事务开始时(第一次
SELECT
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制语句执行时)创建的,并且在整个事务的生命周期内保持不变。这意味着,即使其他事务在这期间修改并提交了数据,当前事务的后续
SELECT
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制查询仍然会看到事务开始时的那个一致快照。MVCC在这里彻底解决了“不可重复读”的问题。结合InnoDB的Next-Key Locks,它还能有效地防止“幻读”。

不适用或较少依赖MVCC来实现读一致性的隔离级别:

READ UNCOMMITTED (RU): 这个隔离级别是最宽松的。它允许一个事务读取其他事务尚未提交的数据,也就是允许“脏读”。在这种情况下,MVCC的机制——即通过
undo log
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制来查找旧版本以提供一致性视图——就显得不那么重要了,或者说,它被刻意绕过了。数据库会直接读取最新的、可能尚未提交的数据版本,而不会去判断其可见性。显然,这牺牲了数据的一致性来换取最高的并发度(因为几乎不需要等待)。SERIALIZABLE: 这是最高的隔离级别,它通过强制事务串行执行来避免所有并发问题,包括脏读、不可重复读和幻读。实现
SERIALIZABLE
登录后复制登录后复制隔离级别,MySQL通常会通过对所有
SELECT
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制语句自动添加共享锁(
LOCK IN SHARE MODE
登录后复制),或者在
SELECT
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制语句中使用
FOR UPDATE
登录后复制或
FOR SHARE
登录后复制显式加锁。这意味着,读操作也会像写操作一样,通过加锁来阻塞其他事务的写操作,从而保证数据的一致性。在这种情况下,MVCC的多版本机制在提供读一致性方面的作用就被锁机制所取代了。虽然MVCC的底层机制可能仍然存在,但其核心的非阻塞读特性在这里并没有被用于实现隔离。它本质上回到了传统的锁机制来确保串行化。

所以,我们可以看到,MVCC是InnoDB在

READ COMMITTED
登录后复制登录后复制登录后复制和
REPEATABLE READ
登录后复制登录后复制登录后复制登录后复制登录后复制登录后复制这两个隔离级别下实现高并发和数据一致性的核心技术。而在
READ UNCOMMITTED
登录后复制,它被“忽略”;在
SERIALIZABLE
登录后复制登录后复制,它被更严格的锁机制所“替代”,以达到更高的隔离要求。理解这一点,对于我们选择合适的隔离级别,优化数据库性能至关重要。

以上就是MVCC(多版本并发控制)在MySQL中是如何工作的?的详细内容,更多请关注乐哥常识网其它相关文章!

相关标签: mysql 数据恢复 数据访问 并发请求 有锁 mysql for select 指针 线程 delete 并发 数据库
MVCC(多版本并发
go语言错误处理 golang错误和异常
相关内容
发表评论

游客 回复需填写必要信息