MySQL 事务隔离级别的详细教程

8 阅读6分钟

你想要一份关于 MySQL 事务隔离级别的详细教程,重点理解 READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ(MySQL 默认)、SERIALIZABLE 这四种隔离级别的含义、区别、问题场景和实际用法,我会用通俗易懂的语言+实操案例帮你彻底搞懂这个核心知识点。

一、前置基础:为什么需要事务隔离级别?

事务隔离级别是为了解决多事务并发执行时出现的脏读、不可重复读、幻读三大问题,不同隔离级别对这三类问题的解决能力不同,同时也会影响数据库的并发性能(隔离级别越高,并发性能越低)。

先明确三个核心问题的定义:

  • 脏读:一个事务读取到另一个事务未提交的数据(比如A转账给B,事务没提交,B却看到余额增加了,之后A回滚,B看到的就是“脏数据”)。
  • 不可重复读:同一个事务内,多次读取同一数据,结果不一致(比如A事务第一次读余额是100,期间B事务修改并提交了余额为200,A再读就变成200)。
  • 幻读:同一个事务内,多次执行同一查询(比如统计符合条件的行数),结果行数不一致(比如A事务统计有10条订单,期间B事务插入了1条新订单并提交,A再统计就变成11条)。

二、MySQL 四大事务隔离级别详解

MySQL 中可以通过以下命令查看/设置隔离级别:

-- 查看当前会话的隔离级别(MySQL 8.0+)
SELECT @@TRANSACTION_ISOLATION;
-- 查看全局隔离级别
SELECT @@GLOBAL.TRANSACTION_ISOLATION;

-- 设置当前会话的隔离级别(临时生效)
SET SESSION TRANSACTION ISOLATION LEVEL [隔离级别];
-- 设置全局隔离级别(永久生效,需重启MySQL)
SET GLOBAL TRANSACTION ISOLATION LEVEL [隔离级别];

下面逐个讲解四大隔离级别,所有案例都基于以下测试表

-- 先创建测试表并插入数据
CREATE TABLE account (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(20),
  balance INT
);
INSERT INTO account (name, balance) VALUES ('张三', 1000);
1. READ UNCOMMITTED(读未提交)
  • 核心特点:最低隔离级别,允许一个事务读取另一个事务未提交的数据。
  • 解决问题:无(会出现所有并发问题)。
  • 存在问题:脏读、不可重复读、幻读都可能发生。
  • 实操案例
    • 会话1(事务A):开启事务,修改数据但不提交
      -- 会话1
      SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
      START TRANSACTION; -- 开启事务
      UPDATE account SET balance = 2000 WHERE name = '张三';
      -- 不执行COMMIT,事务未提交
      
    • 会话2(事务B):读取数据,能看到未提交的修改
      -- 会话2
      SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
      START TRANSACTION;
      SELECT balance FROM account WHERE name = '张三'; -- 结果是2000(脏数据)
      
    • 会话1回滚事务:
      -- 会话1
      ROLLBACK; -- 回滚修改
      
    • 会话2再读:
      -- 会话2
      SELECT balance FROM account WHERE name = '张三'; -- 结果变回1000,出现脏读
      
  • 适用场景:几乎不用(仅适用于对数据准确性要求极低、追求极致并发的场景)。
2. READ COMMITTED(读已提交)
  • 核心特点:只能读取到其他事务已提交的数据,解决了脏读问题。
  • 解决问题:脏读。
  • 存在问题:不可重复读、幻读。
  • 实操案例(不可重复读)
    • 会话1(事务A):开启事务,第一次读取数据
      -- 会话1
      SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
      START TRANSACTION;
      SELECT balance FROM account WHERE name = '张三'; -- 结果:1000
      
    • 会话2(事务B):修改并提交数据
      -- 会话2
      SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
      START TRANSACTION;
      UPDATE account SET balance = 2000 WHERE name = '张三';
      COMMIT; -- 提交事务
      
    • 会话1(事务A):同一事务内再次读取
      -- 会话1
      SELECT balance FROM account WHERE name = '张三'; -- 结果:2000(不可重复读)
      COMMIT;
      
  • 适用场景:Oracle、SQL Server 默认隔离级别,适合对脏读敏感、能接受不可重复读的业务(比如普通查询场景)。
3. REPEATABLE READ(可重复读,MySQL InnoDB 默认)
  • 核心特点:同一个事务内,多次读取同一数据,结果始终一致(即使其他事务修改并提交),解决了脏读、不可重复读问题。
  • 解决问题:脏读、不可重复读。
  • 存在问题:理论上存在幻读(但 MySQL InnoDB 通过 MVCC + 间隙锁解决了幻读,实际使用中几乎不会遇到)。
  • 实操案例(解决不可重复读)
    • 会话1(事务A):开启事务,第一次读取数据
      -- 会话1
      SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
      START TRANSACTION;
      SELECT balance FROM account WHERE name = '张三'; -- 结果:1000
      
    • 会话2(事务B):修改并提交数据
      -- 会话2
      SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
      START TRANSACTION;
      UPDATE account SET balance = 2000 WHERE name = '张三';
      COMMIT; -- 提交事务
      
    • 会话1(事务A):同一事务内再次读取
      -- 会话1
      SELECT balance FROM account WHERE name = '张三'; -- 结果仍为1000(可重复读)
      COMMIT; -- 提交后再读,才会看到2000
      SELECT balance FROM account WHERE name = '张三'; -- 结果:2000
      
  • 适用场景:MySQL 默认级别,适合绝大多数业务场景(电商、后台管理系统等),兼顾一致性和并发性能。
4. SERIALIZABLE(串行化)
  • 核心特点:最高隔离级别,所有事务串行执行(加锁,同一时间只有一个事务能操作数据),解决所有并发问题。
  • 解决问题:脏读、不可重复读、幻读(全部解决)。
  • 存在问题:并发性能极差(相当于单线程操作),容易出现锁等待、死锁。
  • 实操案例(解决幻读)
    • 会话1(事务A):开启事务,统计符合条件的行数
      -- 会话1
      SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
      START TRANSACTION;
      SELECT COUNT(*) FROM account WHERE balance > 500; -- 结果:1(只有张三的1000)
      
    • 会话2(事务B):尝试插入新数据(会被阻塞,直到会话1提交/回滚)
      -- 会话2
      SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
      START TRANSACTION;
      INSERT INTO account (name, balance) VALUES ('李四', 800);
      -- 此处会卡住,直到会话1提交/回滚
      
    • 会话1提交后,会话2的插入才会执行:
      -- 会话1
      COMMIT;
      -- 会话2此时插入成功
      COMMIT;
      
  • 适用场景:极少使用,仅适用于对数据一致性要求极高、并发量极低的场景(比如金融核心交易的关键步骤)。

三、四大隔离级别对比表

隔离级别脏读不可重复读幻读并发性能适用场景
READ UNCOMMITTED最高几乎不用
READ COMMITTED较高普通查询、非核心业务
REPEATABLE READ中等绝大多数业务(MySQL 默认)
SERIALIZABLE最低金融核心交易、高一致性场景

注:✅ 表示会出现该问题,❌ 表示不会出现。