MySQL事务隔离级别详解,读提交可重复读串行化

前言

做后端开发的同学肯定都听说过事务隔离级别,但是很多同学搞不清楚读未提交、读提交、可重复读、串行化这四个级别到底有什么区别,也不知道自己项目应该用哪个级别。

很多面试的时候也经常被问到:MySQL的默认隔离级别是什么?能解决什么问题?很多同学答不上来。

这篇文章就把MySQL的事务隔离级别从头到尾讲清楚,看完之后你就彻底搞懂了。

一、先复习一下事务的ACID特性

讲隔离级别之前,先复习一下事务的四个特性,也就是ACID:

  1. 原子性(Atomicity):事务里的操作要么全部成功,要么全部失败回滚
  2. 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏
  3. 隔离性(Isolation):多个事务之间互相隔离,不能互相干扰
  4. 持久性(Durability):事务提交之后,修改是永久的

我们今天讲的隔离级别,就是跟第三个特性"隔离性"有关的。隔离性的程度不同,就有了不同的隔离级别。

二、并发事务会带来什么问题

为什么需要隔离级别?因为多个事务同时操作数据库的时候,会出现各种问题。

常见的并发问题有三个:

1. 脏读

脏读就是:一个事务读到了另一个事务还没提交的数据。

比如:

  • 事务A把某条数据从1改成了2,但是还没提交
  • 事务B读了这条数据,读到的是2
  • 然后事务A回滚了,数据又变回了1
  • 事务B读的那个2就是脏数据,这就是脏读

2. 不可重复读

不可重复读就是:一个事务里,两次读同一条数据,结果不一样。

比如:

  • 事务A第一次读某条数据,值是1
  • 事务B把这条数据改成了2,并且提交了
  • 事务A第二次再读这条数据,值变成了2
  • 同一个事务里,两次读同一条数据结果不一样,这就是不可重复读

3. 幻读

幻读就是:一个事务里,两次查询的结果集不一样。

比如:

  • 事务A查询id > 5的记录,查到了5、6两条
  • 事务B插入了一条id=7的记录,并且提交了
  • 事务A再查一次,发现多了一条id=7的
  • 这就是幻读

注意:不可重复读和幻读的区别:

  • 不可重复读:同一条数据,两次读结果不一样(修改导致的)
  • 幻读:查询的结果集变多或者变少了(插入/删除导致的)

三、四个事务隔离级别

为了解决上面说的这三个问题,SQL标准定义了四个隔离级别,级别越高,越能解决问题,但是并发性能越差。

1. 读未提交(Read Uncommitted)

最低的隔离级别。一个事务可以读到另一个事务还没提交的数据。

能解决什么问题: 啥也解决不了
会出现什么问题: 脏读、不可重复读、幻读都可能出现

这个级别基本上没人用,所以就不多说了。

2. 读提交(Read Committed,RC)

一个事务只能读到另一个事务已经提交的数据。

能解决什么问题: 解决了脏读
还会出现什么问题: 不可重复读、幻读

Oracle默认就是这个隔离级别。

3. 可重复读(Repeatable Read,RR)

一个事务里,多次读同一条数据,结果是一样的。

能解决什么问题: 解决了脏读、不可重复读
还会出现什么问题: 幻读

注意:MySQL的InnoDB引擎在RR级别下,通过间隙锁解决了幻读问题,所以MySQL的RR级别实际上可以完全解决幻读。

MySQL默认就是这个隔离级别。

4. 串行化(Serializable)

最高的隔离级别。所有事务一个一个排队执行,完全串行。

能解决什么问题: 脏读、不可重复读、幻读全都解决了
缺点: 性能太差了,并发度最低,基本上没人用

四、四个隔离级别对比表

给大家整理了一个表格,一目了然:

隔离级别 脏读 不可重复读 幻读 性能
读未提交 ❌ 可能出现 ❌ 可能出现 ❌ 可能出现 最好
读提交(RC) ✅ 解决了 ❌ 可能出现 ❌ 可能出现 比较好
可重复读(RR) ✅ 解决了 ✅ 解决了 ✅ 解决了(MySQL InnoDB) 比较差
串行化 ✅ 解决了 ✅ 解决了 ✅ 解决了 最差

五、MySQL默认的隔离级别

很多同学面试的时候被问到"MySQL默认的隔离级别是什么",答不上来。

记住:MySQL InnoDB默认的隔离级别是可重复读(RR)。

注意和Oracle区分一下:Oracle默认的是读提交(RC)。

六、怎么查看当前的隔离级别

登录MySQL之后,执行下面的命令:

-- 查看全局的隔离级别
SELECT @@global.tx_isolation;

-- 查看当前会话的隔离级别
SELECT @@session.tx_isolation;

执行完之后会看到类似这样的结果:

+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+

这就说明当前是可重复读级别。

七、怎么修改隔离级别

临时修改(当前会话)

-- 改成读提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 改成可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

这种修改只对当前连接有效,断开连接之后就恢复了。

全局临时修改

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

这种修改对新连接有效,已经存在的连接不受影响,MySQL重启之后就恢复了。

永久修改

要永久修改的话,需要改配置文件。编辑my.cnf,在[mysqld]下面添加:

[mysqld]
transaction-isolation = READ-COMMITTED

修改完之后重启MySQL服务,就永久生效了。

八、实际项目中应该用哪个级别

很多同学问:实际项目中应该用哪个隔离级别?

一般来说:

  • 如果对并发性能要求高:用读提交(RC)就够了,很多互联网公司都是用RC
  • 如果对数据一致性要求高:用可重复读(RR),MySQL默认就是这个
  • 串行化基本上没人用,性能太差了

其实大部分情况下,用MySQL默认的RR就够了,不用特意改。如果并发特别高,可以考虑改成RC,这样间隙锁就没了,并发性能会好很多。

常见坑

坑1:不知道MySQL默认的隔离级别是RR

很多同学以为MySQL默认是读提交,跟Oracle一样,结果面试答错了。记住:MySQL默认是可重复读(RR)。

坑2:把不可重复读和幻读搞混了

很多同学分不清不可重复读和幻读。记住:

  • 不可重复读:同一条数据被修改了,两次读结果不一样
  • 幻读:结果集的行数变多或者变少了,是插入/删除导致的

坑3:以为RR级别解决不了幻读

很多同学以为RR级别解决不了幻读,其实MySQL的InnoDB引擎在RR级别下,通过间隙锁是可以解决幻读的。这一点跟标准SQL不一样,MySQL做了增强。

坑4:修改了隔离级别但是没生效

很多同学用SET GLOBAL改了隔离级别,然后用当前连接查,发现还是原来的级别。这是因为SET GLOBAL只对新连接有效,当前连接还是原来的。要当前连接生效的话,用SET SESSION。

总结

MySQL事务隔离级别的核心知识点:

  1. 并发事务的三个问题:脏读、不可重复读、幻读
  2. 四个隔离级别:读未提交、读提交、可重复读、串行化,级别越高越安全,性能越差
  3. 脏读:读到了别的事务还没提交的数据
  4. 不可重复读:同一个事务里,两次读同一条数据结果不一样(修改导致的)
  5. 幻读:同一个事务里,两次查询的结果集不一样(插入/删除导致的)
  6. MySQL InnoDB默认是可重复读(RR),并且通过间隙锁解决了幻读
  7. 查看隔离级别:SELECT @@tx_isolation
  8. 修改隔离级别:SET SESSION/GLOBAL TRANSACTION ISOLATION LEVEL ...
  9. 实际项目用RR或者RC就够了,串行化性能太差没人用

事务隔离级别是数据库的基础知识点,不管是面试还是实际开发,都是必须掌握的。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-5 08:51