如何利用MySQL中InnoDB的MVCC机制实现高并发非阻塞读?

小瑶同学_3808

小瑶同学_3808

2026-09-07

395人浏览

原创

普通 select 不加锁也能读到“正确”数据,是因为 mvcc 通过 read view 判断行版本可见性,沿 roll_pointer 遍历 undo log 获取事务启动时的一致性快照,实现非阻塞读。

如何利用mysql中innodb的mvcc机制实现高并发非阻塞读?

普通 SELECT 就是高并发非阻塞读的实现入口,前提是隔离级别设为 READ COMMITTED 或 REPEATABLE READ,且不显式加锁。

为什么普通 SELECT 不加锁还能读到“正确”的数据?

MVCC 不靠锁,靠的是每个事务启动时生成的 Read View,它记录了当前活跃事务 ID 列表、最小未提交事务 ID(m_ids)、最大已提交事务 ID(max_trx_id)等关键信息。当执行 SELECT 时,InnoDB 沿着每行的 DB_ROLL_PTR 向上遍历版本链,用当前事务的 Read View 去判断哪个版本可见——不是最新版,而是“对这个事务而言合法的历史版”。

这意味着:事务 A 的 SELECT 完全不碰事务 B 正在修改的行锁,B 可以继续 UPDATE 并生成新版本;A 读取的是 B 修改前的快照,互不等待。

  • 可重复读(RR)下,Read View 在事务第一个快照读时创建,后续所有 SELECT 都复用它 → 同一事务内多次读结果一致
  • 读已提交(RC)下,每次 SELECT 都新建 Read View → 能看到其他事务刚提交的新版本
  • 如果事务中混用了 SELECT ... FOR UPDATE,那这条语句会触发当前读,走加锁流程,MVCC 失效

哪些操作会绕过 MVCC 直接加锁?

只要语句明确要求“最新状态+排他性”,InnoDB 就放弃快照,转为当前读并加锁。这类操作不会享受 MVCC 的非阻塞优势:

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载
  • SELECT ... FOR UPDATE 和 SELECT ... LOCK IN SHARE MODE:即使没修改数据,也锁定当前最新行
  • INSERT、UPDATE、DELETE:必然修改数据,需定位最新版本并加 X 锁或 U 锁
  • 任何带 WHERE 条件但无法使用索引的 SELECT:可能触发全表扫描+隐式锁升级,间接影响并发

注意:UPDATE t SET x = x + 1 WHERE id = 123 先要读 id=123 的最新值(当前读),再更新——这里第一步就跳出了 MVCC 快照读逻辑。

如何验证某次 SELECT 是否走了 MVCC?

最直接的方式是结合 INFORMATION_SCHEMA.INNODB_TRX 和 INFORMATION_SCHEMA.INNODB_LOCKS(MySQL 5.7+)观察锁持有情况:

  • 开两个事务:事务 A 执行 UPDATE t SET v = 10 WHERE id = 1 但不提交;事务 B 执行 SELECT * FROM t WHERE id = 1
  • 查 INNODB_TRX:事务 B 的 TRX_STATE 应为 RUNNING,且 TRX_ROWS_LOCKED 为 0
  • 查 INNODB_LOCKS(如存在):事务 B 不应出现在锁列表中;事务 A 占有一条 X 锁记录

若事务 B 出现锁等待或 TRX_STATE 是 LOCK WAIT,说明它没走快照读——大概率是隔离级别设成了 READ UNCOMMITTED 或用了覆盖索引失效的写法,导致优化器选错执行路径。

真正容易被忽略的点在于:MVCC 的有效性高度依赖事务粒度和语句写法。长事务会拖住 Read View 中的 m_ids,让大量旧版本无法被 purge,最终撑爆 undo log 空间;而一个看似简单的 SELECT COUNT(*) 如果没走索引,也可能因隐式锁行为破坏并发预期。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

2073

6

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.21

1279

5

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

735

5

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.19

2792

5

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.25

4648

4

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.08

1079

3

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.11

4911

4

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

2023.08.14

4382

7

mysql事务隔离级别
mysql事务隔离级别

mysql规范中定义了四种事务隔离级别,不同的隔离级别对事务的处理有所不同。本专题为大家提供mysql事务隔离级别相关的文章内容,大家可以免费体验。

2023.08.16

5714

11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 178人学习

使用phpenv集成环境安装极致CMS
使用phpenv集成环境安装极致CMS

共2课时 | 286人学习