MySQL事务隔离级别需分清配置位置与生效范围:查会话用SELECT @@transaction_isolation,查全局用SELECT @@global.transaction_isolation;永久配置须在my.cnf的[mysqld]下写transaction-isolation = READ-COMMITTED并重启;运行时SET GLOBAL仅影响新连接,SET SESSION仅限当前会话,且不可在事务中修改。

MySQL 的事务隔离级别不能靠“配一次就全局生效”,必须分清配置位置、生效范围和实际作用时机——改错地方或漏掉重启,SELECT @@transaction_isolation 看到的还是旧值。
查当前隔离级别:别只看 @@transaction_isolation
这条命令返回的是当前会话的值,容易误判全局配置是否生效:
-
SELECT @@transaction_isolation;—— 查当前会话(最常用,但有误导性) -
SELECT @@global.transaction_isolation;—— 查全局默认值(才是配置文件或SET GLOBAL真正影响的目标) - MySQL 5.7.20+ 不再支持
@@tx_isolation,若执行报错Unknown system variable 'tx_isolation',说明必须用新变量名
永久生效:改 my.cnf 必须重启 MySQL
在 [mysqld] 段下加这一行:
transaction-isolation = READ-COMMITTED
注意三点:
- 值必须全大写、用短横线(
READ-COMMITTED),写成read committed或ReadCommitted都会导致 MySQL 启动失败,日志里报unknown variable 'transaction_isolation' - 修改后不重启服务,配置完全不生效——已存在的连接仍用旧级别,新连接也读不到新配置
- 该设置只决定“新连接的默认级别”,不影响任何已建立的会话
运行时临时调整:用 SET GLOBAL 或 SET SESSION
这两条命令不用重启,但作用范围完全不同:
-
SET GLOBAL transaction_isolation = 'READ-COMMITTED';—— 立即影响所有后续新建连接,但对当前已连上的客户端无效 -
SET SESSION transaction_isolation = 'SERIALIZABLE';—— 只改当前连接,断开即丢,适合调试单个业务逻辑 - 如果在事务已经开始后(比如已执行
BEGIN或第一条UPDATE)再执行SET TRANSACTION ISOLATION LEVEL,MySQL 会静默忽略,不报错也不生效 - 某些 ORM(如 Django)会在连接初始化时强制覆盖隔离级别,此时手动
SET SESSION可能被框架重置,得查 ORM 文档确认是否允许透传
REPEATABLE-READ 不等于防幻读,别被默认值骗了
MySQL 默认是 REPEATABLE-READ,但它靠 Next-Key Lock + MVCC 防幻读,仅对“已有记录范围”有效:
- 如果其他事务插入了一条**新记录**并提交,当前事务后续
SELECT仍可能看到它(幻读) - 想真正杜绝幻读,要么加
SELECT ... FOR UPDATE显式锁范围,要么升到SERIALIZABLE(代价高,慎用) - 线上环境基本不用
READ-UNCOMMITTED,因为普通SELECT不加锁,脏读可立刻复现,不是理论风险
最常被忽略的一点:隔离级别不是“设完就稳”,它和 binlog 格式、主从复制模式、ORM 行为交织在一起——比如 READ-COMMITTED 在 ROW 格式 binlog 下才真正匹配语义,否则 CDC 工具可能捕获到不一致变更。


















