事务隔离级别决定的是“能看到什么”,而非执行顺序;它通过MVCC快照(read view)控制SELECT可见的数据版本,而执行顺序由锁机制、语句类型及加锁时机决定。

事务隔离级别决定的是「能看到什么」,不是「执行顺序」
MySQL 的事务隔离级别(READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE)不控制 SQL 语句的执行先后,而是约束一个事务中 SELECT 能读到哪些版本的数据。真正影响执行顺序的是锁机制、MVCC 快照生成时机和语句是否触发加锁(比如 UPDATE、SELECT ... FOR UPDATE)。
常见误解是:设成 REPEATABLE READ 就能保证两个事务按提交顺序“串行执行”。实际不是——它们仍可并发执行,只是读视图被冻结在事务第一次 SELECT 或开启时,导致“读一致性”,而非“执行一致性”。
不同隔离级别下,同一时间点的 SELECT 结果为何不同
关键在事务开启时获取的 MVCC 快照(read view)范围不同:
-
READ UNCOMMITTED:不创建 read view,SELECT直接读最新行版本(可能脏读) -
READ COMMITTED:每次SELECT都新建 read view,只能看到已提交的、在本语句开始前已提交的事务修改 -
REPEATABLE READ:事务第一次SELECT时创建 read view,后续所有SELECT复用它(所以不会出现不可重复读) -
SERIALIZABLE:隐式为所有SELECT加共享锁,强制阻塞写操作,实际变成串行执行
例如两个事务 T1 和 T2 同时运行:
DESTOON B2B网站管理系统是一套完善的B2B(电子商务)行业门户解决方案。系统基于PHP+MySQL开发,采用B/S架构,模板与程序分离,源码开放。模型化的开发思路,可扩展或删除任何功能;创新的缓存技术与数据库设计,可负载千万级别数据容量及访问。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION; SELECT * FROM t WHERE id = 1; -- 此刻生成 read view -- 即使 T2 此后更新并提交 id=1 的行,T1 再 SELECT 仍看到旧值
执行顺序受锁和语句类型影响,比隔离级别更直接
即使在 REPEATABLE READ 下,UPDATE 或 SELECT ... FOR UPDATE 仍会尝试加行锁或间隙锁,导致阻塞。这时“谁先拿到锁”就决定了实际执行顺序,跟隔离级别无关。
-
INSERT可能触发插入意向锁,与间隙锁冲突 -
UPDATE t SET x=1 WHERE y=5在无索引列y上会升级为表锁 -
SELECT ... LOCK IN SHARE MODE和FOR UPDATE显式申请锁,立即参与锁竞争
典型现象:事务 A 执行 UPDATE t SET v=1 WHERE id=10 未提交,事务 B 在相同行上执行 UPDATE 或 SELECT ... FOR UPDATE 就会被挂起,直到 A 提交或回滚——这个等待链就是真实执行顺序的体现。
容易忽略的关键点:autocommit 和 START TRANSACTION 的时机
MySQL 默认 autocommit = 1,单条 DML(如 UPDATE)会自动成为独立事务。此时隔离级别只作用于该语句本身,没有“跨语句一致性”可言。只有显式 START TRANSACTION 或 BEGIN 后,才进入多语句事务上下文,隔离级别才有持续效果。
- 忘记关
autocommit就直接写多个UPDATE,误以为它们在一个事务里 - 在存储过程中调用
START TRANSACTION,但没处理异常回滚,导致连接长期持有锁 -
SET SESSION TRANSACTION ISOLATION LEVEL ...只对后续事务生效,不影响当前已开启的事务
验证当前事务状态最直接的方式是查:
SELECT @@autocommit, @@transaction_isolation, trx_state FROM information_schema.INNODB_TRX WHERE trx_mysql_thread_id = CONNECTION_ID();









