事务已提交却查不到数据,最常见原因是查询与提交不在同一连接或隔离级别导致快照固化:RR级别下事务启动后生成ReadView,后续提交不可见,需新开事务或改用READ COMMITTED。

事务已提交,但 SELECT 查不到——先确认是不是“同一个事务”
MySQL 中“已提交却查不到”,最常见原因是:你执行 COMMIT 的那个连接(Session),和后续执行 SELECT 的不是同一个。比如在应用里用连接池,或脚本中反复 mysql -u ... -e "SELECT",每次都是新连接、新事务,自然看不到前一个 Session 提交的数据——除非隔离级别是 READ COMMITTED 或更低。
检查方法:SELECT CONNECTION_ID(); 对比插入/提交和查询时的连接 ID;或者在同一个 shell 会话里连续操作,避免新开命令行。
- ORM(如 MyBatis)中
openSession(false)创建的是新 Session,不继承前一个事务上下文 - Web 应用里 HTTP 请求之间默认无事务延续性,一次请求结束即事务终结
-
mysql -e是一次性连接,执行完就断开,无法感知其他连接的提交
可重复读(RR)下查不到刚提交的数据——这不是 bug,是快照固化
如果你的 Session A 在 REPEATABLE READ 隔离级别下启动后执行过任意一次 SELECT,它就生成了一个 ReadView 快照。之后无论其他 Session B 是否 COMMIT,只要没开启新事务,A 就一直基于这个旧快照判断可见性——所以“明明提交了,就是看不见”。
这不是延迟,也不是缓存未刷新,而是 MVCC 的设计行为。想看到新数据,只有两个办法:
- 在 Session A 中执行
START TRANSACTION WITH CONSISTENT SNAPSHOT(新建事务并获取新快照) - 或临时切到
READ COMMITTED:SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED,再查
注意:SELECT * FROM t 不会自动更新快照;COMMIT 后也不自动重建——必须显式开启新事务。
autocommit=0 不影响跨 Session 可见性——它只管“你自己”
设 SET autocommit = 0 只是让当前 Session 进入手动提交模式,和“能不能看到别人提交”完全无关。很多人误以为关掉 autocommit 就能“共享事务状态”,其实它连 Session 内部的事务边界都不改变,更不会穿透到别的连接。
典型错误场景:
- Session A 执行
SET autocommit = 0; INSERT ...;但没COMMIT→ 其他 Session 当然看不到 - Session A 已
COMMIT,Session B 却仍查不到 → 问题不在 autocommit,而在 B 的隔离级别或是否复用旧事务
真正影响跨 Session 可见性的,只有两件事:对方是否 COMMIT,以及你当前事务的隔离级别和 ReadView 生成时机。
INSERT 新行后查不到——可能是幻读防护机制在起作用
在 RR 级别下,如果 Session B INSERT 了一条新记录并 COMMIT,Session A 却仍然查不到,大概率是因为 A 的事务启动早于 B 的插入时间,且 A 的 ReadView 中 low_limit_id 高于 B 的 trx_id,导致该行被判定为“未来事务产生”,直接过滤掉。
这不是数据丢了,而是 MVCC 主动屏蔽了“幻象”。要绕过它,只能:
- 让 Session A 用
SELECT ... FOR UPDATE或SELECT ... LOCK IN SHARE MODE加锁读(触发当前读,跳过快照) - 改用
READ COMMITTED级别(每次SELECT都建新快照) - 业务上避免依赖“查无结果就插入”,改用
INSERT IGNORE或ON DUPLICATE KEY UPDATE
最易被忽略的一点:RR 下的“查不到”往往不是数据问题,而是你没意识到自己正活在一个静态快照里——它不随外部变化而更新,只随你主动开启新事务而重置。


















