MySQL默认隔离级别是REPEATABLE READ,未提交的变更对其他会话不可见,这是MVCC通过ReadView机制实现的确定性行为,而非延迟或bug。

MySQL 默认隔离级别是 REPEATABLE READ,未提交的变更对其他会话不可见——这不是 bug,是 MVCC 机制保障的确定性行为。
为什么 SELECT 查不到别人刚 INSERT/UPDATE 的数据?
根本原因不是“没写入磁盘”或“缓存没刷”,而是 InnoDB 在读取时会基于当前事务的 ReadView 过滤掉所有未提交事务产生的版本。其他会话即使执行完全相同的 SELECT,看到的也是自己事务启动时刻已提交的数据快照。
- 事务 A 执行
INSERT INTO t VALUES (1)后未COMMIT - 事务 B 此时执行
SELECT * FROM t,结果里没有1 - 这不是延迟,也不是网络问题,是 MVCC 在底层自动做了可见性判断
- 哪怕事务 A 和 B 连的是同一台 MySQL 实例、同一张表、同一个索引,结果依然如此
怎么确认是不是事务卡住了没提交?
别只看 SHOW PROCESSLIST——它不显示事务状态。真正有效的是查系统表:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_state = 'RUNNING';
-
trx_state = 'RUNNING'且trx_started时间很早(比如几小时以前),说明这个事务可能被遗忘提交了 -
trx_mysql_thread_id可用于后续KILL操作(如KILL 12345) - ORM 场景下尤其容易漏:Django 的
@transaction.atomic或 SQLAlchemy 的session.commit()忘调用,事务就一直挂着
READ COMMITTED 和 REPEATABLE READ 的关键区别在哪?
两者都靠 MVCC,但 ReadView 创建时机不同,直接影响“什么时候能看到别人提交的数据”:
-
READ COMMITTED:每次SELECT都新建一个ReadView→ 能立刻看到其他事务刚COMMIT的变更 -
REPEATABLE READ(MySQL 默认):只在事务中**第一次查询时**创建ReadView→ 后续所有SELECT都复用它,所以整个事务内看到的数据版本始终一致 - 降级到
READ COMMITTED并不能解决“查不到未提交数据”的问题,只是让“查到已提交数据”的时机更早
最容易被忽略的底层事实
未提交事务的修改确实没落盘,但它在内存中已生成脏页、Undo Log 已写、Redo Log Buffer 也已记录——这些都不是“没发生”,而是数据库在刻意控制可见性边界。排查时若还盯着 innodb_buffer_pool_size 或 query_cache,就完全跑偏了。
真正要盯的是:当前会话是否处于显式事务中(BEGIN 之后、COMMIT 之前),以及别的会话是否依赖这个未提交状态做逻辑判断——后者才是实际业务出错的根源。

















