必须显式用set命令设置事务隔离级别,因配置文件和set global仅影响新连接,已存在连接仍保持原级别;serializable会使select加共享锁,引发阻塞与死锁风险,需全面评估锁行为。

不能靠配置文件“设完就生效”,必须在会话里用 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 显式开启,否则事务仍是默认的 REPEATABLE READ。
为什么 SET GLOBAL 不起作用?
MySQL 的 transaction_isolation 配置项(如写在 my.cnf 里)只影响新建立连接的默认值,对已存在的连接完全无效。你改了配置、没重启 MySQL、也没新建连接,SELECT @@transaction_isolation 还是显示旧值——这是最常踩的坑。
- 全局设置仅对后续新建连接生效:
SET GLOBAL transaction_isolation = 'SERIALIZABLE' - 已有连接必须单独执行:
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE - 也可以在事务开始前直接设:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE,然后START TRANSACTION
SERIALIZABLE 下 SELECT 就会加读锁,不是“只锁写”
和 REPEATABLE READ 不同,SERIALIZABLE 会让普通 SELECT 语句也隐式加上共享锁(类似加了 LOCK IN SHARE MODE),所以并发查询也会相互阻塞。
- 事务 A 执行
SELECT * FROM users WHERE id = 1后,事务 B 对同一行执行UPDATE会被挂起,直到 A 提交或回滚 - 事务 A 和 B 都只做
SELECT,通常不阻塞;但只要其中一方后续尝试INSERT/UPDATE,另一方的SELECT就可能被锁住(尤其涉及范围扫描时) - 它不依赖 MVCC 快照,而是靠锁机制实现串行化,所以
SELECT的性能开销明显上升
表级锁风险:多个 SERIALIZABLE 事务可能互相卡死
虽然 InnoDB 在 SERIALIZABLE 下仍以行锁为主,但一旦查询涉及全表扫描、无索引条件或间隙判断,很容易升级为临键锁(Next-Key Lock)甚至表级锁效果——尤其是两个事务都试图修改同一张表时。
- 事务 A 插入一条记录,事务 B 此时也尝试插入,B 会等待(超时后报
Lock wait timeout exceeded) - 如果 A 和 B 先都执行了
SELECT ... FROM t(无 WHERE 或无索引),再各自 INSERT,极大概率触发死锁或长时间等待 - 注意:
SERIALIZABLE不等于“绝对不会幻读”,它靠锁防止其他事务插入,但如果应用层没控制好顺序,还是可能因锁等待顺序导致业务逻辑异常
真正要用 SERIALIZABLE,得接受它带来的吞吐下降和锁等待——不是加个级别就万事大吉,而是要把整个事务路径里的读、写、范围条件都重新评估一遍锁行为。多数场景下,用 SELECT ... FOR UPDATE 配合 REPEATABLE READ 更可控。











