MySQL MVCC 详解 原文链接https://www.rendering.me/blog/7CRB6eMySQL MVCC 详解维基百科上关于 MVCC 的介绍多版本并发控制(Multiversion concurrency control MCC 或 MVCC)是数据库管理系统常用的一种并发控制也用于程序设计语言实现事务内存。MVCC意图解决读写锁造成的多个、长时间的读操作饿死写操作问题。每个事务读到的数据项都是一个历史快照并依赖于实现的隔离级别。写操作不覆盖已有数据项而是创建一个新的版本直至所在操作提交时才变为可见。快照隔离使得事务看到它启动时的数据状态。MVCC 的核心是“数据多版本”即同一数据在系统中可以存在多个版本每个事务看到的数据是特定版本的快照。具体来说读操作无需加锁直接读取数据的某个历史版本避免了与写操作的冲突。写操作只锁定当前操作的数据不影响其他事务的读操作。这种机制使得读写操作可以并发执行大大提高了数据库的并发性能。MVCC 实现机制MySQL中MVCC的实现基于以下基石隐藏字段InnoDB 中每一行数据除了我们定义的字段外还会存在一些额外的隐藏列DB_TRX_ID事务ID表示插入或更新该行的最后一个事务的事务标识符DB_ROLL_PTR回滚指针回滚指针指向写入回滚段的 undo log 记录DB_ROW_ID行ID随着新行插入而单调增加。事务ID每次启动一个事务InnoDB 会为其分配一个唯一递增的事务 ID。事务 ID 用于判断数据版本的可见性。回滚段Rollback Segment与 undo 日志当数据被修改时InnoDB 会将旧数据复制到回滚段中并通过DB_ROLL_PTR指针链接到 undo 日志。这些历史版本数据用于支持事务回滚和 MVCC 的读操作。Read View读视图每个读操作启动时会生成一个 Read View包含当前活跃事务的列表。Read View 用于判断事务能看到哪些数据版本。Read View 包含以下四个关键属性creator_trx_id当前创建 Read View 的事务 ID。用于标识生成该 Read View 的事务。trx_ids活跃事务列表创建 Read View 时当前所有未提交的事务 ID 列表即活跃事务。这些事务的修改对当前 Read View 可能不可见需要根据规则判断。low_limit_id创建 Read View 时系统中已分配的最大事务 ID 1。表示大于等于该值的事务 ID 在 Read View 创建后生成对当前 Read View 不可见。low_limit_no删除版本号用于判断行的删除操作是否对当前事务可见与 purge 操作相关。核心是前三个属性。对于读已提交事务隔离级别在事务中每次执行查询都会重新创建一次Read View因此可能会读取到其它事务提交的数据。对于可重复读事务隔离级别在事务中只会创建一次Read View后续每次查询都使用第一次创建的Read View因此保证了每次读取的数据都是一致的。流程数据准备当前事务隔离级别为读已提交createtablet1(idintprimarykey,c2int);insertintot1values(1,100);事务1STARTTRANSACTION;updatet1setc2200wheret11;事务2 开启并进行查询STARTTRANSACTION;select*fromt1whereid1;事务3STARTTRANSACTION;updatet1setc2300wheret11;事务2第二次次查询select*fromt1whereid1;事务1提交COMMIT;事务2第三次查询select*fromt1whereid1;commit;假设上述事务1的事务ID120事务2的事务ID130事务3的事务ID140。对于事务2第一次查询时事务1先一步开启进行数据修改并且没有提交MVCC 的处理流程如下生成 Read Viewcreator_trx_id事务 2 的 ID 130。trx_ids活跃事务列表包含事务 1为 120。low_limit_id创建 Read View 时系统中已分配的最大事务 ID 1 假定为131。查询操作获取到最新行中的DB_TRX_ID120为事务1修改可见性判断120 在trx_ids中因此当前数据未提交对于当前事务不可见根据DB_ROLL_PTR查找undo log事务ID为110未被其它事务修改数据可见因此事务2第一次查询结果为 100。对于事务2第二次查询时新开启了事务3修改了数据并且也没有提交MVCC 的处理流程如下生成 Read Viewcreator_trx_id事务 2 的 ID 130。trx_ids活跃事务列表包含事务1事务3为 120140。low_limit_id创建 Read View 时系统中已分配的最大事务 ID 1假定为141。查询操作获取到最新行中的DB_TRX_ID140为事务3修改可见性判断140 在trx_ids中因此当前数据未提交对于当前事务不可见根据DB_ROLL_PTR查找undo log事务ID为120仍然在trx_ids中被事务1修改对于当前事务不可见继续根据DB_ROLL_PTR查找undo log事务ID为110未被其它事务修改数据可见因此事务2第二次查询结果为 100。对于事务3第三次查询时事务1提交事务3仍然开启MVCC 的处理流程如下生成 Read Viewcreator_trx_id事务 2 的 ID 130。trx_ids活跃事务列表由于事务1已提交因此只包含事务3为140。low_limit_id创建 Read View 时系统中已分配的最大事务 ID 1假定为141。查询操作获取到最新行中的DB_TRX_ID140为事务3修改可见性判断140 在trx_ids中因此当前数据未提交对于当前事务不可见根据DB_ROLL_PTR查找undo log事务ID为120事务已提交数据可见因此事务2第二次查询结果为 200。