MySQL默认隔离级别是REPEATABLE READ,通过Next-Key Locks与MVCC实现,快照读无幻读,当前读可能幻读;RC级每次快照读取最新版本,易发幻读;RU和SERIALIZABLE极少使用。

MySQL 默认隔离级别是 REPEATABLE READ,但它的实现方式和标准 SQL 不同
MySQL 的 REPEATABLE READ 并不靠锁住所有读取范围来防止幻读,而是用 Next-Key Locks(间隙锁 + 行锁)配合 MVCC 实现。这意味着:同一事务中多次 SELECT 看到的数据快照一致,但新插入的行是否可见,取决于是否落在被锁定的间隙里。
常见误解是认为 REPEATABLE READ 能完全避免幻读 —— 实际上,在「当前读」(如 SELECT ... FOR UPDATE、UPDATE、DELETE)下,间隙锁会阻止其他事务在范围内插入,从而抑制幻读;但在纯「快照读」下,新插入的行对本事务不可见,不是因为被锁住,而是因为 MVCC 只看到事务开始时已存在的版本。
-
READ COMMITTED下每次快照读都重新获取最新已提交版本,所以不会复现「不可重复读」,但幻读更易发生(间隙锁在 RC 下只在唯一索引等少数场景启用) -
READ UNCOMMITTED几乎不用:可能读到未提交数据,SELECT不加任何锁,性能高但业务逻辑极难保证 -
SERIALIZABLE会让普通SELECT隐式加上LOCK IN SHARE MODE,所有读写都串行化,开销大,通常只在极严苛审计场景才考虑
如何查看和修改当前会话或全局隔离级别
隔离级别是会话级变量,可动态调整,但需注意生效时机:修改后只影响后续语句,不影响已开启的事务。
SELECT @@transaction_isolation; -- 返回类似:REPEATABLE-READ(MySQL 8.0+)或 TRANSACTION_ISOLATION(5.7)SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 需 SUPER 权限,且新连接才生效
注意:GLOBAL 设置不会改变当前已连接会话的级别;如果应用使用连接池,改全局后旧连接仍维持原级别,必须重启连接或显式 SET SESSION。
- MySQL 5.7 使用
@@tx_isolation,8.0+ 统一为@@transaction_isolation -
配置文件中设置:在
my.cnf加transaction-isolation = READ-COMMITTED(注意用短横线) - JDBC 连接串可指定:添加
&sessionVariables=transaction_isolation='READ-COMMITTED'
SELECT ... FOR UPDATE 和 SELECT ... LOCK IN SHARE MODE 的锁行为差异
这两者都触发「当前读」,绕过 MVCC 快照,直接访问最新行并加锁,但锁类型和兼容性不同:
DESTOON B2B网站管理系统是一套完善的B2B(电子商务)行业门户解决方案。系统基于PHP+MySQL开发,采用B/S架构,模板与程序分离,源码开放。模型化的开发思路,可扩展或删除任何功能;创新的缓存技术与数据库设计,可负载千万级别数据容量及访问。
-
FOR UPDATE在符合条件的记录上加X 锁(排他锁),同时在扫描范围加Gap Lock(除非唯一索引等效精确匹配) -
LOCK IN SHARE MODE加S 锁(共享锁),允许其他事务加 S 锁,但阻塞 X 锁;同样有间隙锁行为 - 若查询条件无索引,MySQL 会退化为全表扫描 + 全表记录加锁,极易引发锁等待甚至死锁
典型陷阱:执行 SELECT * FROM t WHERE name = 'foo' FOR UPDATE,但 name 列没有索引 → 锁住整张表所有行,而不是仅匹配行。
幻读到底在什么情况下会发生?
幻读指「同一事务中,前后两次相同范围的 SELECT 返回行数不同」。它是否发生,取决于读类型和隔离级别:
- 在
REPEATABLE READ下,快照读(普通SELECT)不会出现幻读 —— 因为始终读取事务启动时的快照 - 但在当前读下(如
SELECT ... FOR UPDATE),如果另一个事务在间隙中插入了新行,本事务再次执行相同当前读时会看到新行 → 这就是幻读 -
READ COMMITTED下,快照读每次取最新已提交版本,所以不仅可能幻读,还可能出现不可重复读
真正难处理的是「基于幻读做业务判断」的场景,比如先查有没有订单,再插入 —— 即使用了 SELECT ... FOR UPDATE,若没锁住对应间隙,仍可能被并发插入打破逻辑。这时候得靠唯一约束或应用层分布式锁兜底。









