MySQL事务隔离级别需用SET命令显式设置,配置文件仅影响新连接;READ UNCOMMITTED导致脏读,REPEATABLE READ默认但不完全防幻读,SERIALIZABLE强制串行化代价高。

MySQL中设置事务隔离级别的两种方式
全局或会话级隔离级别必须通过 SET 命令显式指定,不能靠配置文件“一劳永逸”生效(my.cnf 中的 transaction_isolation 只影响新连接的默认值,已有连接不受影响)。
常见误操作是改了配置却没重启 MySQL 或没重新建连接,结果 SELECT @@transaction_isolation 还显示旧值。
- 会话级(当前连接有效):
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED - 全局级(影响后续所有新连接):
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ - 查看当前会话级别:
SELECT @@transaction_isolation - 查看全局默认值:
SELECT @@global.transaction_isolation
READ UNCOMMITTED 导致脏读的真实场景
这个级别下,事务 A 未提交的修改,事务 B 就能读到——不是理论风险,而是立刻可复现的问题。比如库存扣减场景:A 扣 100 件但回滚,B 却基于这“-100”做了发货判断。
InnoDB 实际很少用它,因为连 SELECT 都不加锁,性能虽高但业务逻辑极易崩坏。线上环境基本禁用。
- 触发条件:两个事务并发,A 修改某行未提交,B 在此期间执行
SELECT - 验证方法:在 B 的事务中查出 A 未提交的数据,再等 A
ROLLBACK,B 再查发现数据“消失” - 注意:
SELECT ... FOR UPDATE或LOCK IN SHARE MODE在该级别下仍会加锁,但普通SELECT不会
REPEATABLE READ 是 InnoDB 默认级别,但不等于“完全可重复”
它靠 MVCC + Next-Key Lock 解决幻读,但仅限于当前已存在的记录范围;如果其他事务插入了**新记录**并提交,本事务后续 SELECT 仍可能看到(即“幻读”未被完全屏蔽),除非显式加锁。
典型翻车点:分页查询时,第二页数据突然出现第一页的“漏网之鱼”,就是因为新插入的行落在了原查询范围之间。
- 快照读(普通
SELECT):基于事务开启时的 Read View,不感知新插入 - 当前读(
SELECT ... FOR UPDATE、UPDATE、DELETE):会触发 Next-Key Lock,阻塞范围内插入 - 想真正避免幻读?要么用
SELECT ... FOR UPDATE锁住范围,要么升级到SERIALIZABLE(但代价是并发大幅下降)
SERIALIZABLE 强制串行化,但代价是锁表级行为
它会让所有普通 SELECT 隐式变成 SELECT ... LOCK IN SHARE MODE,意味着读操作也会加共享锁,写操作加排他锁,冲突变多,超时和死锁概率显著上升。
别只看“最安全”,得看业务是否真的需要——比如银行核心账务系统可能用,但电商商品详情页绝对不该用。
- 启用后,两个事务同时
SELECT同一行不会阻塞,但一个SELECT和一个UPDATE就会互等 -
INSERT会被阻塞,如果目标位置已被另一个事务的SELECT ... LOCK IN SHARE MODE锁住 - 监控时注意
Innodb_row_lock_waits和Innodb_deadlocks指标突增
InnoDB 的隔离级别不是越高压越好,关键看业务对一致性、性能、开发复杂度的取舍。最容易被忽略的是:同一张表上不同语句(快照读 vs 当前读)行为差异巨大,不理解这点,光调级别解决不了问题。











