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

想确认当前会话的隔离级别?直接运行 SELECT @@transaction_isolation; 就行。但这里有个关键提醒——这个查询结果,反映的只是MySQL层面的配置快照,它未必等同于你的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')这种查询,如果 `status` 不是唯一索引,间隙锁的范围可能没有完全覆盖所有可能的插入位置,导致其他事务插入了符合条件的新行。 - 显式加锁的漏洞:即使你用了
SELECT ... FOR UPDATE,如果锁的范围设计不足,没有锁住所有未来可能插入数据的“间隙”,幻读依然会钻空子。 - 隔离级别的本质差异:这里有个对比:在
READ-COMMITTED级别下,每次SELECT都会生成一个新的ReadView,所以出现幻读的概率相对更高。而REPEATABLE-READ会复用事务启动时的那个ReadView,理论上确实更稳定一些。 - 真正的“绝对安全”:如果业务上必须100%杜绝幻读,那么只有两条路:要么将隔离级别提升到代价高昂的
SERIALIZABLE,要么在应用层通过分布式锁等手段来保证。数据库层面的“绝对安全”,往往意味着性能的巨大牺牲,需要仔细权衡。
所以,别再只盯着 SELECT @@transaction_isolation; 的返回值了。那只是一个静态配置。真实的读取行为,是由MVCC快照的生成时机、索引的类型、是否使用了加锁语句、以及ORM框架有没有暗中干预等一系列因素共同决定的——这些,才是线上出现数据不一致问题的真正“推手”。
