mysql事务隔离级别设置不生效,90%是因未作用于目标事务:必须在start transaction前用set session设置,且表引擎需为innodb、autocommit=0,并确保连接复用时初始化sql正确配置。

MySQL事务隔离级别设置不生效,90%的情况不是命令写错了,而是根本没作用在目标事务上。 你执行了 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED,但后续查询依然表现出 REPEATABLE READ 的行为——这不是 MySQL bug,是连接、会话或引擎层面的隐性约束在起作用。
确认当前会话是否真的用了你设的级别
很多人设完就以为生效了,其实 SET SESSION 只影响“当前连接”的后续事务,且必须在事务开启前设置。一旦 START TRANSACTION 已执行,再改隔离级别无效。
- 查当前会话实际生效的级别:
SELECT @@transaction_isolation;或SHOW VARIABLES LIKE 'transaction_isolation'; - 查当前连接是否已启动事务:
SELECT @@in_transaction;返回 1 表示事务已开始,此时SET SESSION不会改变本次事务的隔离行为 - 验证方式:新开一个连接(比如新 terminal 或客户端 tab),先
SET SESSION,再START TRANSACTION,最后执行读操作,才能看到效果
InnoDB 表引擎不支持?那隔离级别就是摆设
隔离级别只对支持事务的存储引擎有效。如果你的表是 MyISAM、MEMORY 或旧版本的 Aria,无论你怎么设 REPEATABLE READ,都等同于自动提交 + 无锁读 —— 因为它们压根没有 MVCC 和行级锁。
- 检查表引擎:
SHOW CREATE TABLE your_table_name;看ENGINE=后面是不是InnoDB - 快速修复:
ALTER TABLE your_table_name ENGINE=InnoDB; - 注意:如果表里有全文索引或空间索引,
ALTER可能失败,需先删索引再重建
autocommit=1 时,SET SESSION 基本白设
当 autocommit=1(MySQL 默认),每条 SELECT、UPDATE 都是独立事务,SET SESSION TRANSACTION ISOLATION LEVEL 只影响下一个显式事务(即下一次 START TRANSACTION),而不是当前语句。
- 验证:
SELECT @@autocommit;,返回 1 就是开的 - 临时关闭:
SET autocommit = 0;,之后所有 DML 都进入隐式事务,直到你COMMIT或ROLLBACK - 关键点:隔离级别必须在
START TRANSACTION之前设置;如果用autocommit=0,则首次 DML 自动开启事务,此时也要确保SET SESSION在它之前
全局设置 vs 会话设置,别混用还指望它管用
SET GLOBAL TRANSACTION ISOLATION LEVEL 只影响新建立的连接,对已有连接完全无效。而很多框架(如 Spring Boot 的 @Transactional)默认复用连接池里的连接,这些连接很可能早就初始化好了,用的是启动时的全局默认值(通常是 REPEATABLE READ)。
- 查全局默认:
SELECT @@global.transaction_isolation; - 改全局(需 SUPER 权限):
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; - 但更稳妥的做法是:在应用层连接池配置里指定初始化 SQL,例如 HikariCP 的
connection-init-sql设为SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED - PHP PDO 用户注意:
PDO::ATTR_AUTOCOMMIT => false必须显式设置,否则beginTransaction()前的语句仍走 autocommit
真正让隔离级别“看得见效果”的关键,不在命令本身,而在你是否控制住了连接生命周期、事务边界和存储引擎这三根杠杆。漏掉任意一环,SET 就只是往日志里写了一行无意义的文本。











