MySQL InnoDB默认隔离级别是REPEATABLE READ,其事务级快照保证同一事务内多次SELECT结果一致;READ COMMITTED采用语句级快照,可能导致不可重复读;SERIALIZABLE自动为SELECT加共享锁,显著降低并发性。

MySQL InnoDB 默认隔离级别是 REPEATABLE READ
启动一个新连接后,执行 SELECT @@transaction_isolation; 或 SELECT @@tx_isolation;(旧版本),返回值通常是 'REPEATABLE-READ'。这是 InnoDB 的默认设置,不是 MySQL Server 层的全局默认(Server 层默认是 REPEATABLE READ,但实际生效由引擎决定)。
READ COMMITTED 能避免不可重复读,但需注意 MVCC 行为变化
InnoDB 在 READ COMMITTED 下,每个 SELECT 语句都会创建新的快照(即“语句级快照”),而 REPEATABLE READ 是“事务级快照”——第一次 SELECT 就确定了整个事务可见的数据版本。
- 这意味着在
READ COMMITTED中,同一事务内两次SELECT可能返回不同结果(如果其他事务已提交修改) -
UPDATE/DELETE语句在READ COMMITTED下只看到已提交版本,不会像REPEATABLE READ那样基于事务初态做一致性读 - 某些场景下,
READ COMMITTED的锁范围更小(例如非唯一条件更新时,可能不加间隙锁),但具体取决于查询是否命中索引
SERIALIZABLE 会强制将所有普通 SELECT 转为 SELECT ... LOCK IN SHARE MODE
这不是加个表锁那么简单。InnoDB 在 SERIALIZABLE 下,对没有显式加锁的 SELECT 语句自动加上共享锁(S 锁),导致并发读写阻塞明显升高。
- 例如:事务 A 执行
SELECT * FROM t WHERE id = 10;,事务 B 同时执行UPDATE t SET x=1 WHERE id = 10;,B 会被阻塞直到 A 提交或回滚 - 即使查询走的是二级索引,也可能触发临键锁(next-key lock),进一步限制并发
- 除非业务强依赖绝对顺序一致性,否则一般不建议全局启用
SERIALIZABLE
修改隔离级别要注意作用域和生效时机
隔离级别可以在会话级、全局级甚至单条语句级设置,但行为有差异:
- 会话级:
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;—— 只影响当前连接后续事务 - 全局级:
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;—— 新建连接继承该值,已有连接不受影响 - 事务级:
START TRANSACTION WITH CONSISTENT SNAPSHOT;不指定隔离级别,仍按当前会话设置;若要覆盖,必须在START TRANSACTION前用SET TRANSACTION ISOLATION LEVEL ... - MySQL 8.0+ 支持在
SELECT语句末尾加FOR UPDATE或LOCK IN SHARE MODE,但这属于加锁语义,不改变事务隔离级别本身
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; START TRANSACTION; SELECT * FROM orders WHERE status = 'pending'; -- 使用 READ COMMITTED 快照 UPDATE orders SET status = 'processing' WHERE id = 123; COMMIT;
真正容易被忽略的是:隔离级别只约束“读可见性”和“锁行为”,它不能替代应用层的逻辑校验。比如两个事务同时读到同一行并各自更新,在 READ COMMITTED 下可能产生覆盖写,这不是隔离级别能解决的——得靠乐观锁(version 字段)或应用层重试机制。










