什么是多版本控制
MySQL的多版本控制(简称MVCC)是一种并发控制机制,它允许在不锁定资源的情况下进行数据的读取和修改。MVCC通过在数据库中保存数据的多个版本来实现这一点,使得不同的事务可以访问他们的数据快照版本来保证数据访问的安全性
基本概念
1、当前读和快照读
在MySQL中,特别是使用InnoDB存储引擎时,“当前读”(Current Read)是一种读取操作,它不仅读取数据,还会对数据加上适当的锁,以保证数据的一致性和事务的隔离性。当前读通常涉及到的是读取到的最新数据,并且可能对数据加锁以防止其他事务对数据进行修改。
具体来说,当前读有以下几个特点:
- 最新版本:当前读获取的是数据的最新版本,可以读取到其他事务已经提交的更改。
- 加锁机制:当前读需要使用排他锁(写锁)来保证数据的一致性,这会影响其他事务对相同数据的并发操作。
- 事务隔离性:不同的隔离级别(如READ COMMITTED、REPEATABLE READ、SERIALIZABLE)会对当前读的行为有不同的影响。
- 常见操作:在MySQL中,使用以下SQL语句会触发当前读:
SELECT … FOR UPDATE
、SELECT … LOCK IN SHARE MODE
,以及UPDATE
、INSERT
、DELETE
等操作。
在SERIALIZABLE
隔离级别下,所有读取操作都会变成当前读,而不仅仅是那些显式加上锁的读取操作。当前读是一种带有锁机制的读取操作,旨在确保读取的数据一致性并防止其他事务对这些数据进行并发修改。
2、快照读
在MySQL中,特别是在使用InnoDB存储引擎时,“快照读”(Snapshot Read)是一种读取操作,它允许事务读取到数据的一致性视图,而不受其他并发事务的影响。这种读取方式不涉及对数据行加锁,因此不会阻塞其他事务对数据的修改,提高了数据库的并发性能。
快照读的主要特点包括:
- 一致性视图:快照读提供了一个数据的一致性快照,即事务在开始时“拍摄”的数据状态。即使其他事务在该事务执行期间修改了数据,该事务也能读取到它开始时的数据状态。
- 非阻塞读取:由于快照读不涉及对数据行的加锁,它不会阻塞其他事务对数据的修改。这减少了锁争用,提高了并发性能。
- 隔离级别依赖:快照读的行为依赖于事务的隔离级别。在
READ COMMITTED
隔离级别下,快照读会读取到最新提交的数据版本。而在REPEATABLE READ
隔离级别下,快照读会读取到事务开始时的数据版本,即使其他事务在该事务执行期间提交了更改。 - 版本链:InnoDB通过维护数据的版本链来实现快照读。每个数据行都保存了多个版本,事务可以根据自己的隔离级别和开始时间来选择正确的版本。
- 垃圾回收:InnoDB的MVCC机制会负责清理不再需要的旧数据版本,以避免无限增长。
- 常见操作:在MySQL中,普通的
SELECT
查询默认就是快照读,除非指定了FOR UPDATE
或LOCK IN SHARE MODE
。
什么是undolog
在数据库系统中,undo log
(撤销日志)是一种重要的日志记录机制,用于处理事务中的回滚操作和保持数据的一致性。它是事务日志(transaction log)的一部分,记录了事务进行修改之前的数据状态,以便在事务失败或需要回滚时能够恢复到原始状态。
以下是undo log
的一些关键特性:
- 回滚操作:当一个事务需要被回滚时,
undo log
提供了必要的信息来撤销事务中已经进行的修改,确保数据能够恢复到事务开始前的状态。 - 一致性保证:在事务执行过程中,如果系统发生故障(如宕机、断电等),
undo log
可以帮助数据库恢复到一致的状态,确保数据的完整性。 - **多版本并发控制(MVCC)**:在支持MVCC的数据库系统中,
undo log
也用于维护数据的多个版本,使得不同的事务可以访问到它们需要的数据版本,而不会相互干扰。 - 非锁定读取:在某些数据库系统中,
undo log
允许非锁定读取,即在不锁定数据的情况下进行数据读取,这有助于提高数据库的并发性能。 - 节省存储空间:
undo log
通常只记录必要的信息来恢复数据,而不是记录完整的数据副本,这样可以节省存储空间。 - 事务隔离:在不同的事务隔离级别下,
undo log
的使用方式可能不同,以确保事务的隔离性。 - 垃圾回收:在事务提交后,
undo log
中不再需要的部分可以被垃圾回收机制清除,以释放存储空间。
在MySQL的InnoDB存储引擎中,undo log
是实现事务和MVCC的关键组件。InnoDB的undo log
分为两种类型:
-
插入undo log:记录了插入操作的逆操作,用于处理插入操作的回滚。
Read View
实现mvcc的关键 事务读取到对应版本的read view
在
REPEATABLE READ
隔离级别下,Read View
通常在以下几种情况下被创建:
- 事务开始时:当事务开始时,如果没有其他
Read View
存在,InnoDB会创建一个新的Read View
。 - 第一次读取操作时:如果事务在执行过程中还没有创建
Read View
,那么在第一次执行读取操作时会创建一个。 -
Read View的工作原理
Read View
包含以下关键信息:
- 事务ID列表:记录了在
Read View
创建时所有已经启动的事务的ID。 - 低水位标记:表示
Read View
创建时的最小事务ID。 - 高水位标记:表示
Read View
创建时的最大事务ID。
当事务尝试访问数据时,Read View
会根据以下规则决定事务可以看到哪个版本的数据:
- 如果数据的事务ID小于低水位标记:表示该数据版本在
Read View
创建之前就已经存在,事务可以看到这个版本。 - 如果数据的事务ID大于高水位标记:表示该数据版本是在
Read View
创建之后由其他事务创建的,当前事务不可见。 - 如果数据的事务ID在低水位和高水位之间:需要检查该事务是否在
Read View
的事务ID列表中。如果在列表中,事务可以看到这个版本;如果不在,事务不可见。