会话级隔离级别只影响当前连接后续开启的新事务,不改变已启动事务的隔离级别;事务启动时隔离级别即锁定,SET SESSION仅更新会话默认值,不回溯生效。

会话级隔离级别只影响新事务,不改变已有事务的上下文
MySQL 的 transaction_isolation 是会话变量(SESSION 级别),修改它只对当前连接后续开启的事务生效。已经 BEGIN 或正在执行的事务,其隔离级别在事务启动时就已锁定,不会因后续 SET SESSION transaction_isolation = ... 而改变。
常见错误现象:
- 执行
SET SESSION transaction_isolation = 'READ-COMMITTED';后,立即执行SELECT,却发现仍按旧级别(如REPEATABLE-READ)读取快照 - 应用连接池复用连接,连接建立后设置了隔离级别,但后续业务逻辑中未显式开启新事务,误以为整个连接都“切换”了级别
使用场景:
- 调试时临时切隔离级别做对比测试
- 某些中间件或 ORM 在连接初始化时设置会话级隔离级别,但业务代码未注意事务边界
关键点:
- 事务的隔离级别在
START TRANSACTION或第一条 DML/SELECT 语句执行时确定,不是在连接建立时 -
SELECT @@transaction_isolation返回的是当前会话的默认值,不是当前事务的实际级别(除非当前无活跃事务) - 若需确保某事务用指定级别,必须在
BEGIN前设置SET SESSION transaction_isolation,且不能有其他语句干扰
如何验证当前事务实际使用的隔离级别?
不能只查 @@transaction_isolation —— 它反映的是会话默认值,不是运行中事务的真实行为。真正有效的方式是结合现象反推:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 在事务内连续两次读同一行,中间由另一事务修改并提交:若第二次读到新值 → 实际为
READ-COMMITTED;若仍是旧值 → 实际为REPEATABLE-READ - 执行
SELECT * FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID(),看TRANSACTION_ISOLATION字段(MySQL 8.0.14+ 支持,5.7 不提供该字段) - 用
SHOW ENGINE INNODB STATUS\G查看当前事务的Trx isolation level行(仅限 InnoDB,且需事务处于活跃状态)
为什么 SET GLOBAL 不影响已有连接?
SET GLOBAL transaction_isolation = '...' 只改变新建立连接的默认值,对已存在的连接完全无效。这是 MySQL 变量作用域的基本规则:GLOBAL 影响未来连接,SESSION 影响当前连接后续事务,两者都不回溯修改已启动的事务。
容易踩的坑:
- 运维脚本里只改了
GLOBAL,却没重启应用或刷新连接池,结果所有长连接仍沿用旧默认值 - 监控告警只采集
@@global.transaction_isolation,误判“配置已生效”,实际业务流量全走错级别 - 在连接池配置里设了
initSql=SET SESSION...,但某些连接因异常未执行该语句,导致部分连接隔离级别不一致
Spring 应用中特别要注意的传播陷阱
Spring 的 @Transactional 默认继承当前线程绑定的连接的会话级别,但如果你手动调用了 setTransactionIsolation(...) 或在 TransactionDefinition 中指定了隔离级别,它会在事务开启前强制执行 SET SESSION transaction_isolation —— 这个动作只对本次事务生效,不影响连接池里其他借用该连接的请求。
性能与兼容性影响:
-
READ-COMMITTED下每次SELECT都生成新 MVCC 快照,比REPEATABLE-READ多一次 snapshot 创建开销,高并发下可能轻微增加 CPU 消耗 - MySQL 5.7 和 8.0 对隔离级别字符串格式不兼容:
REPEATABLE_READvsREPEATABLE-READ,硬编码字符串时容易出错 - MyBatis 等框架若在
select标签里写了fetchSize或流式查询,可能绕过事务上下文,导致隔离行为不可预期
最常被忽略的一点:事务一旦开始,它的隔离级别就固化了,无论你之后怎么 SET、怎么换连接池配置、甚至怎么重启应用——只要那个事务还活着,它就按最初启动时的规则跑完。想改?只能等它结束,或者 kill connection 强制中断。

















