news 2026/8/29 20:36:33

MySQL 中的事务隔离级别有哪些?默认的事务隔离级别是什么?为什么选择这个级别?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL 中的事务隔离级别有哪些?默认的事务隔离级别是什么?为什么选择这个级别?

面试题考点分析

  1. 能否准确说出 InnoDB 支持的四种事务隔离级别,以及每种级别解决哪些并发问题。
  2. 是否真正理解脏读、不可重复读、幻读三个概念及其区别。
  3. 是否知道 MySQL 默认隔离级别是 REPEATABLE READ,并能说清楚选择它的原因。
  4. 是否掌握 MVCC、ReadView、Next-Key Lock 等底层机制,把「可重复读」和「避免幻读」正确关联起来。
  5. 能否在 Java、JDBC 或 Spring 中正确查看和配置隔离级别。

一、标准回答

MySQL 的 InnoDB 存储引擎支持四种事务隔离级别:READ UNCOMMITTED(读未提交)、READ COMMITTED(读已提交)、REPEATABLE READ(可重复读)和 SERIALIZABLE(串行化)。其中,默认的事务隔离级别是 REPEATABLE READ(可重复读)

事务隔离级别的作用,是在事务并发执行时,平衡「数据一致性」与「并发性能」两个目标。隔离级别越低,事务间互相可见的数据越多,一致性越弱,但并发性能越好;隔离级别越高,数据一致性越强,但锁冲突和等待越多,吞吐量越低。

隔离级别能否解决脏读能否解决不可重复读能否解决幻读
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READMySQL 通过 Next-Key Lock 基本解决
SERIALIZABLE

面试时可以直接给结论:“MySQL InnoDB 默认使用可重复读,而不是 SQL 标准推荐的读已提交。它通过 MVCC 保证同一事务内多次读取结果一致,并借助 Next-Key Lock 基本解决幻读,因此在安全和并发性能之间取得了较好的平衡。”这句话既说明了作用,也点出了 MySQL 和 SQL 标准的差异,是面试官比较认可的回答口径。

二、核心原理

2.1 并发事务引起的三大问题

理解隔离级别之前,要先理解并发事务可能带来的三类数据错误:

  • 脏读:事务 A 读到了事务 B 尚未提交的数据。如果 B 之后回滚,A 读到的就是「脏数据」。READ COMMITTED 及以上级别可解决。
  • 不可重复读:事务 A 内多次读取同一行,期间事务 B 修改并提交了该行,导致 A 两次读取结果不一致。REPEATABLE READ 及以上级别可解决。
  • 幻读:事务 A 按某个条件查询一组行,期间事务 B 插入或删除了满足该条件的行,导致 A 再次查询时出现「凭空多出或消失的行」。通常需要 SERIALIZABLE,MySQL 在 RR 级别下通过 Next-Key Lock 基本解决。

简单记忆:脏读针对「未提交」,不可重复读针对「已提交的修改」,幻读针对「已提交的插入/删除」

2.2 MVCC 如何实现可重复读

InnoDB 采用MVCC(多版本并发控制)实现快照读。每行记录隐藏两个系统列:DB_TRX_ID(最近修改该行的事务 ID)和DB_ROLL_PTR(指向回滚段的 undo log 指针)。事务读取时不会直接加锁,而是根据当前事务的ReadView判断某行版本是否可见:

  • READ COMMITTED:每次查询都会生成新的 ReadView,因此能看到其他事务已提交的最新数据,但可能发生不可重复读。
  • REPEATABLE READ:事务第一次查询时生成 ReadView,并复用至事务结束,因此同一事务内多次快照读结果一致,实现了可重复读。

可以类比为:RR 级别在事务开始时「拍一张数据快照」,事务内后续读取都基于这张快照,外部事务的提交修改对当前事务不可见。官方文档明确说明,InnoDB 通过这种机制避免了加读锁带来的性能开销。

2.3 Next-Key Lock 如何解决幻读

MVCC 只能保证快照读(普通 SELECT)的可重复读,而当前读(如SELECT ... FOR UPDATE、UPDATE、DELETE、INSERT)需要依赖锁机制。InnoDB 的Next-Key Lock是「行锁 + 间隙锁(Gap Lock)」的组合:

  • 行锁:锁定具体的已存在记录。
  • 间隙锁:锁定记录之间的空隙范围,阻止其他事务在该范围内插入新记录。

例如,事务执行SELECT * FROM t WHERE id BETWEEN 10 AND 20 FOR UPDATE时,不仅会锁定 id 为 10 到 20 的已存在行,还会锁定这些行之间的间隙,从而阻止其他事务在该范围内插入满足条件的新行,达到防止幻读的效果。这也是 MySQL 的 RR 级别比 SQL 标准定义的 RR「更严格」的根本原因。

三、应用场景

3.1 日常开发场景

  • 默认业务场景:大多数 CRUD 业务直接使用数据库默认的 REPEATABLE READ 即可,既能保证事务内读取一致,又无需额外配置。
  • 金融、账户余额类场景:涉及资金变动、余额扣减时,保持 RR 级别,并通过SELECT ... FOR UPDATE对行加锁,避免并发扣减导致超卖或余额不一致。
  • 高并发读多写少场景:如商品浏览、内容展示,如果对一致性要求不苛刻,可将隔离级别降低为 READ COMMITTED,减少间隙锁带来的锁冲突和死锁概率。

3.2 企业真实场景

  • 电商下单扣库存:先查询库存,再扣减库存。若使用 READ COMMITTED,可能出现同一库存被两个事务重复扣减;使用 RR 加行锁则可避免不可重复读与并发超卖。
  • 账户转账:从账户 A 扣款、向账户 B 加款必须在一个事务内完成。RR 级别配合行锁,可避免扣款成功后加款前其他事务读取到中间状态。
  • 报表统计与对账:统计类 SQL 需要读取稳定的数据快照,RR 级别保证同一事务内多次聚合查询结果一致,避免统计口径漂移。

四、使用方式

4.1 JDBC 查看和设置隔离级别

import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; public class TransactionIsolationDemo { public static void main(String[] args) throws Exception { // 1. 四种隔离级别对应的 JDBC 常量 System.out.println("READ_UNCOMMITTED = " + Connection.TRANSACTION_READ_UNCOMMITTED); System.out.println("READ_COMMITTED = " + Connection.TRANSACTION_READ_COMMITTED); System.out.println("REPEATABLE_READ = " + Connection.TRANSACTION_REPEATABLE_READ); System.out.println("SERIALIZABLE = " + Connection.TRANSACTION_SERIALIZABLE); Connection conn = getConnection(); // 2. 查看当前连接默认隔离级别(MySQL 默认输出 4,即 REPEATABLE_READ) int defaultLevel = conn.getTransactionIsolation(); System.out.println("默认隔离级别: " + defaultLevel); // 3. 显式设置为可重复读 conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); // 4. 关闭自动提交,开启手动事务 conn.setAutoCommit(false); try (Statement stmt = conn.createStatement()) { stmt.executeUpdate("UPDATE account SET balance = balance - 100 WHERE id = 1"); stmt.executeUpdate("UPDATE account SET balance = balance + 100 WHERE id = 2"); conn.commit(); System.out.println("事务提交成功"); } catch (SQLException e) { conn.rollback(); System.out.println("事务回滚"); throw e; } finally { conn.close(); } } private static Connection getConnection() throws SQLException { String url = "jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai"; return DriverManager.getConnection(url, "root", "123456"); } }

4.2 SQL 层面查看和设置

-- 查看当前会话隔离级别 SELECT @@transaction_isolation; -- 查看全局默认隔离级别 SELECT @@global.transaction_isolation; -- 设置当前会话隔离级别为可重复读 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- 设置全局默认隔离级别 SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

4.3 Spring 中的配置

import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; @Service public class AccountService { @Transactional(isolation = Isolation.REPEATABLE_READ, rollbackFor = Exception.class) public void transfer(Long fromId, Long toId, Long amount) { // 执行扣款、加款逻辑 } }

4.4 执行流程与注意事项

执行流程可以概括为:获取连接 → 查看或设置隔离级别 → 关闭自动提交 → 执行一组业务 SQL → 提交或回滚 → 释放连接

  • 隔离级别要在事务开始前设置。如果事务已经开始,再修改隔离级别对当前正在进行的事务不一定生效。
  • 必须通过setAutoCommit(false)显式开启事务,否则每条 SQL 自动提交,事务边界和隔离级别就失去了意义。
  • 使用连接池时要格外注意:连接归还后可能被其他线程复用,隔离级别是连接级属性,不会自动恢复默认值,建议在归还连接前将隔离级别重置为默认值。
  • getTransactionIsolation()返回的是 JDBC 常量值,其中TRANSACTION_REPEATABLE_READ对应数值 4,TRANSACTION_READ_COMMITTED对应数值 2,可以用来与原默认值做比对。

五、扩展延伸

5.1 与 SQL 标准及主流数据库的对比

SQL 标准定义的 REPEATABLE READ 只要求解决不可重复读,并没有强制解决幻读。MySQL 因为引入了 Next-Key Lock,在 RR 级别下也能基本避免幻读,因此比标准定义更严格。不同数据库的默认隔离级别也不同:

数据库默认事务隔离级别
MySQL InnoDBREPEATABLE READ
OracleREAD COMMITTED
PostgreSQLREAD COMMITTED
SQL ServerREAD COMMITTED

5.2 选择 REPEATABLE READ 的原因

  • 历史兼容性:早期 MySQL 主从复制依赖 statement-based binlog,RR 级别能保证主从执行顺序一致,避免复制数据不一致。
  • 一致性足够强:RR 配合 Next-Key Lock 已基本解决幻读,安全性接近 SERIALIZABLE,能满足大多数业务对数据的一致性要求。
  • 并发性能更好:与 SERIALIZABLE 的完全串行化相比,RR 采用 MVCC 快照读,读操作不加锁,写操作只需要行锁和间隙锁,并发吞吐量高得多。

5.3 优缺点与实际开发注意事项

RR 的优点是一致性高、能解决脏读、不可重复读以及大部分幻读;缺点是间隙锁会扩大锁范围,降低并发度,并可能增加死锁概率。

  • 尽量使用索引:间隙锁的范围与索引条件强相关,缺少合适索引时,InnoDB 可能锁住更多记录甚至更宽的范围,要保证 WHERE 条件命中索引。
  • 控制事务时长:RR 的长事务会长时间持有 ReadView 和 undo log,可能导致 undo log 膨胀和锁等待,应避免在事务内做远程调用或慢查询。
  • 关注死锁:间隙锁和行锁的粒度不同,多个事务交叉加锁容易死锁,可通过统一加锁顺序、缩短事务、配置死锁检测和重试来缓解。
  • 高并发业务可评估降级为 RC:互联网高并发场景下,很多团队将隔离级别改为 READ COMMITTED,配合 row 格式 binlog 保证复制一致性,以换取更高的并发性能。

六、面试追问

追问 1:既然 RR 能解决幻读,那 SERIALIZABLE 还有什么用?

回答思路:先承认 MySQL 的 RR 确实能解决绝大多数幻读,再指出两者的实现机制和性能差异。

标准答案:MySQL 的 RR 通过 MVCC 解决快照读幻读,通过 Next-Key Lock 解决当前读幻读,确实覆盖了绝大多数场景。但 SERIALIZABLE 会把所有普通 SELECT 也变成加锁读(相当于隐式加共享锁),彻底串行化事务,实现理论上的完全隔离。代价是并发性能急剧下降。因此只有在一致性要求极高、可以接受较低并发的场景下才使用 SERIALIZABLE。

追问 2:快照读和当前读有什么区别?

回答思路:从是否加锁、是否走 MVCC 两个维度区分。

标准答案:普通 SELECT 属于快照读,通过 MVCC 读取 ReadView 对应的数据版本,不加锁,性能高。当前读包括SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODE、UPDATE、DELETE、INSERT,读取的是数据的最新提交版本,并通过行锁或 Next-Key Lock 保证操作期间数据不被并发修改。这也是 RR 级别下,单纯 SELECT 和带 FOR UPDATE 的 SELECT 可能读到不同结果的根源。

追问 3:为什么互联网公司常常把隔离级别改成 READ COMMITTED?

回答思路:从并发性能和复制机制两个角度解释,并说明前提条件。

标准答案:READ COMMITTED 每次查询都会生成新的 ReadView,且没有间隙锁,锁范围更小,并发吞吐量更高,死锁概率也更低。早期 MySQL 依赖 statement-based binlog 必须使用 RR 保证主从一致;而现在普遍使用 row 格式 binlog,记录的是行变更结果,主从可以保持一致,因此用 RC 换取更高并发成为优化选择。这是一个典型的「一致性换性能」的工程取舍。

追问 4:如何查看和修改 MySQL 的默认隔离级别?

回答思路:分「查看」和「修改」两步,说明会话级与全局级的区别。

标准答案:查看当前会话用SELECT @@transaction_isolation;,查看全局默认值用SELECT @@global.transaction_isolation;。修改会话级用SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;,修改全局默认值用SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;。需要注意,全局修改只影响之后新建的连接,已存在的连接不会改变;也可以修改配置文件my.cnf中的transaction-isolation参数实现持久化。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/29 20:34:47

从失忆到第二大脑:AI Agent 记忆系统的三次范式跃迁

从失忆到第二大脑:AI Agent 记忆系统的三次范式跃迁 2022 年,GPT-4 让机器第一次拥有了通用的语言与推理能力。2024 年,RAG 与工具调用让 AI 长出了手和眼。而 2025 年之后,一个更根本的问题浮出水面——AI 开始需要"记忆&qu…

作者头像 李华
网站建设 2026/8/29 20:31:21

蓝桥杯嵌入式国赛ADC按键设计:从电路原理到软件滤波实战

1. 项目概述:ADC按键在蓝桥杯嵌入式国赛中的核心地位在蓝桥杯嵌入式设计与开发国赛的赛场上,ADC按键这个题目几乎可以算作一个“保留节目”。乍一看,题目要求很简单:用ADC(模数转换器)来检测多个按键的状态…

作者头像 李华
网站建设 2026/8/29 20:26:49

HDMI数据的接收发送实验(二十五)

一、 概况 本章节根据显示器时序标准来生成1024 x 768 60Hz的三色彩条。 二、标准时序参数水平方向参数: parameter H_SYNC_TIME 136; // 行同步脉冲宽度:136 个像素时钟 H_SYNC_TIME 是行同步脉冲的宽度。HSYNC 每行拉低 136 个像素时钟&#xff…

作者头像 李华
网站建设 2026/8/29 20:19:38

林伽一 · AI科技日报 | 2026年08月28日

今日AI行业的技术动态集中在两条主线:算力基础设施重构与智能体开发工具链标准化。算力端,OpenAI首款自研AI芯片Jalapeo首批基准测试公布,其700瓦芯片在速度与能效上均超越英伟达旗舰产品[① The Rundown AI];英伟达同步推出NVLin…

作者头像 李华
网站建设 2026/8/29 20:19:15

C++函数模板:从重复代码到泛型编程的核心利器

1. 从“重复造轮子”到“一劳永逸”:为什么我们需要函数模板?如果你写过一段时间的C,尤其是在处理一些需要为不同类型实现相同逻辑的代码时,肯定有过这样的体验:写一个函数用来交换两个int值,简单明了。过两…

作者头像 李华
网站建设 2026/8/29 20:18:25

常州市本地维修壁挂炉师傅|上门维修壁挂炉电话|故障码不点火维修|本地口碑维修推荐

常州市本地维修壁挂炉师傅|上门维修壁挂炉电话|故障码不点火维修|本地口碑维修推荐常州家里壁挂炉突然不点火、开机报错、暖气不热、热水忽冷忽热、频繁熄火、水压掉压、异响漏水不用慌!切忌反复强制重启或找临时路边师傅维修。常…

作者头像 李华