MySQL事务隔离级别详解,读提交可重复读串行化
时间:2026-10-5 08:51 作者:emer 分类: 无
前言
做后端开发的同学肯定都听说过事务隔离级别,但是很多同学搞不清楚读未提交、读提交、可重复读、串行化这四个级别到底有什么区别,也不知道自己项目应该用哪个级别。
很多面试的时候也经常被问到:MySQL的默认隔离级别是什么?能解决什么问题?很多同学答不上来。
这篇文章就把MySQL的事务隔离级别从头到尾讲清楚,看完之后你就彻底搞懂了。
一、先复习一下事务的ACID特性
讲隔离级别之前,先复习一下事务的四个特性,也就是ACID:
- 原子性(Atomicity):事务里的操作要么全部成功,要么全部失败回滚
- 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏
- 隔离性(Isolation):多个事务之间互相隔离,不能互相干扰
- 持久性(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事务隔离级别的核心知识点:
- 并发事务的三个问题:脏读、不可重复读、幻读
- 四个隔离级别:读未提交、读提交、可重复读、串行化,级别越高越安全,性能越差
- 脏读:读到了别的事务还没提交的数据
- 不可重复读:同一个事务里,两次读同一条数据结果不一样(修改导致的)
- 幻读:同一个事务里,两次查询的结果集不一样(插入/删除导致的)
- MySQL InnoDB默认是可重复读(RR),并且通过间隙锁解决了幻读
- 查看隔离级别:SELECT @@tx_isolation
- 修改隔离级别:SET SESSION/GLOBAL TRANSACTION ISOLATION LEVEL ...
- 实际项目用RR或者RC就够了,串行化性能太差没人用
事务隔离级别是数据库的基础知识点,不管是面试还是实际开发,都是必须掌握的。
遇到问题加QQ23979811 协助处理