直接查当前会话隔离级别用select @@transaction_isolation;查全局用select @@global.transaction_isolation;二者均返回全大写短横线格式字符串(如'read-committed'),且@@transaction_isolation等价于@@session.transaction_isolation。

直接查当前会话的隔离级别,用 SELECT @@transaction_isolation; 就行;但要注意——它不反映 ORM 或连接池初始化后实际生效的值,必须结合使用场景验证。
怎么查当前会话和全局的隔离级别
MySQL 5.7.20+ 推荐统一用 @@transaction_isolation,旧变量名 @@tx_isolation 在新版本可能报 Unknown system variable 'tx_isolation' 错误。
- 查当前会话:
SELECT @@transaction_isolation; - 查全局设置:
SELECT @@global.transaction_isolation; - 注意:
@@session.transaction_isolation和@@transaction_isolation效果一样,都是会话级 - 返回值是字符串,如
'READ-COMMITTED',带单引号、全大写、用短横线分隔,不是read committed或ReadCommitted
SET TRANSACTION ISOLATION LEVEL 失效的常见原因
执行 SET TRANSACTION ISOLATION LEVEL READ COMMITTED; 后仍看到旧行为?大概率是以下某条在作祟:
- 命令必须在事务开始前执行 —— 如果已执行
BEGIN、START TRANSACTION或任意 DML(如UPDATE),再SET就被 MySQL 静默忽略,不报错也不生效 - Django、SQLAlchemy 等 ORM 通常在连接建立时主动覆盖隔离级别,手动
SET会被后续框架 SQL 覆盖 - 连接池(如 HikariCP、Druid)复用连接,会话级设置随连接生命周期结束而丢失,无法跨请求持久
-
SET SESSION transaction_isolation = 'SERIALIZABLE';写法等价,但更显式;若拼错值(如写成'serializable'),MySQL 不报错,但实际设为默认值REPEATABLE-READ
配置文件改 transaction_isolation 为什么重启才生效
在 my.cnf 的 [mysqld] 段下加 transaction_isolation = READ-COMMITTED 是最可靠的全局设置方式,但必须重启 MySQL 进程:
- MySQL 启动时读取配置并初始化全局系统变量;运行中修改配置文件对已加载的变量无影响
- 若语法错误(比如多空格、写成
transaction_isolation= read-committed),MySQL 启动失败,错误日志里会出现unknown variable 'transaction_isolation' - 该设置只影响新建立的连接;已有连接继续使用原隔离级别,直到断开
- 配合
binlog_format = ROW使用时,READ-COMMITTED是官方推荐组合,能避免主从因一致性视图差异导致的数据不一致
为什么 REPEATABLE-READ 下还出现幻读
MySQL 默认的 REPEATABLE-READ 借助 MVCC + 间隙锁(Gap Lock)在多数场景屏蔽幻读,但有明确例外:
- 非唯一索引上的范围查询(如
WHERE status IN ('pending', 'processing'))可能漏锁,导致其他事务插入符合条件的新行 - 显式加锁语句(如
SELECT ... FOR UPDATE)未覆盖所有可能插入位置时,间隙锁范围不足 - 使用
READ-COMMITTED时,每次SELECT都生成新 ReadView,幻读概率更高;而REPEATABLE-READ复用事务启动时的 ReadView,理论上更稳 - 真正要杜绝幻读,得靠
SERIALIZABLE或应用层加分布式锁——数据库层的“绝对安全”代价太高,得权衡
别只盯着 SELECT @@transaction_isolation 的返回值,它只是配置快照;真实读取行为取决于 MVCC 快照生成时机、索引类型、是否加锁、ORM 是否干预——这些才是线上数据不一致的真正推手。











