MySQL事务隔离级别详解

一、事务的ACID特性

在深入了解事务隔离级别之前,先回顾一下数据库事务的四大核心特性——ACID:

特性 英文 说明
原子性(Atomicity) Atomicity 事务中的操作要么全部成功,要么全部失败回滚,不存在部分执行的中间状态
一致性(Consistency) Consistency 事务执行前后,数据库的完整性约束(如主键、外键、业务规则)保持有效
隔离性(Isolation) Isolation 并发事务之间相互隔离,一个事务的执行不能被其他事务干扰
持久性(Durability) Durability 事务提交后,对数据的修改永久保存,即使系统崩溃也不会丢失

关键点:一致性(C)是业务层面的目标,需要原子性(A)、隔离性(I)、持久性(D)这三个机制共同保障。

DDL 本身不支持事务、不能回滚
MySQL 事务里插 DDL = 截断旧事务、提交旧数据、新开新事务

二、什么是事务隔离

事务隔离是数据库事务ACID特性中"I"(Isolation,隔离性)的体现。它定义了并发事务之间相互影响的程度。隔离级别越高,数据一致性越好,但并发性能越差。

三、事务并发带来的问题

在了解隔离级别之前,先看看并发事务可能引发的问题:

问题 说明
脏读(Dirty Read) 读取到其他事务未提交的数据
不可重复读(Non-Repeatable Read) 同一事务中,两次读取同一行数据结果不同(针对 UPDATE)
幻读(Phantom Read) 同一事务中,两次查询结果集行数不同(针对 INSERT/DELETE)

四、四种隔离级别(SQL标准)

SQL标准定义了四种隔离级别,从低到高依次为:

隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED 可能 可能 可能
READ COMMITTED 不可能 可能 可能
REPEATABLE READ 不可能 不可能 可能(SQL标准)
SERIALIZABLE 不可能 不可能 不可能

说明:SQL标准的REPEATABLE READ级别允许幻读,但MySQL InnoDB的RR级别通过MVCC+Next-Key Lock机制实现了对幻读的防护,是对SQL标准的增强。

1. READ UNCOMMITTED(读未提交)

核心规则:允许读取其他事务未提交的数据。

这是最低的隔离级别,几乎不提供任何并发保护。

示例

-- 事务A:更新数据但未提交
BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1;

-- 事务B:读取到了事务A未提交的数据
SELECT balance FROM account WHERE id = 1;  -- 读到的是修改后的值

-- 事务A:回滚
ROLLBACK;

-- 事务B:读到的数据是脏数据(事务A已回滚)
SELECT balance FROM account WHERE id = 1;  -- 数据不一致

适用场景:几乎不使用,仅在需要极高并发且能容忍脏读的场景下考虑。


2. READ COMMITTED(读已提交)

核心规则:只能读取已提交事务的数据,防止脏读。

大多数数据库(如Oracle、SQL Server)的默认隔离级别。

示例

-- 事务A:更新数据但未提交
BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1;

-- 事务B:无法读取到未提交的数据
SELECT balance FROM account WHERE id = 1;  -- 读到的是修改前的值

-- 事务A:提交
COMMIT;

-- 事务B:现在可以读到新值
SELECT balance FROM account WHERE id = 1;  -- 读到新值

存在的问题:不可重复读。同一个事务中,两次读取同一行数据可能得到不同结果。


3. REPEATABLE READ(可重复读)

核心规则:同一事务中,多次读取同一数据结果相同,即使其他事务修改并提交了该数据。

重要说明:此规则仅适用于快照读(普通SELECT)。如果是当前读,会读取最新的已提交数据并加锁。

MySQL(InnoDB)的默认隔离级别。SQL标准的RR级别允许幻读,但InnoDB的RR级别是对SQL标准的增强,通过MVCC+Next-Key Lock共同解决了幻读问题

核心机制

InnoDB在RR级别下,通过两种完全不同的机制分别解决两种读操作的幻读问题:

读操作类型 机制 说明
快照读(普通SELECT) MVCC(多版本并发控制) 事务开启时生成一致性视图(Read View),整个事务期间所有快照读都基于此视图
当前读(SELECT ... FOR UPDATE/LOCK IN SHARE MODE、INSERT、UPDATE、DELETE) Next-Key Lock(临键锁=记录锁+间隙锁) 锁定查询条件对应的索引范围(包括间隙),阻止其他事务插入新行

示例1:快照读的可重复读特性

-- 事务A:开启事务,快照读
BEGIN;
SELECT balance FROM account WHERE id = 1;  -- 快照读,返回1000

-- 事务B:更新数据并提交
BEGIN;
UPDATE account SET balance = 500 WHERE id = 1;
COMMIT;

-- 事务A:再次快照读,结果与第一次相同
SELECT balance FROM account WHERE id = 1;  -- 快照读,仍然返回1000(符合可重复读)

-- 事务A:当前读,读取最新值并加锁
SELECT balance FROM account WHERE id = 1 FOR UPDATE;  -- 当前读,返回500

-- 事务A:提交
COMMIT;

示例2:快照读通过MVCC避免幻读

-- 事务A:开启事务,快照读
BEGIN;
SELECT * FROM user WHERE age > 20;  -- 返回5行(快照读,基于Read View)

-- 事务B:插入新用户并提交
INSERT INTO user (name, age) VALUES ('新用户', 25);
COMMIT;

-- 事务A:再次快照读,不会看到新插入的行(MVCC一致性视图)
SELECT * FROM user WHERE age > 20;  -- 仍然返回5行
COMMIT;

示例3:当前读通过Next-Key Lock避免幻读

-- 事务A:开启事务,当前读(加锁)
BEGIN;
SELECT * FROM user WHERE age > 20 FOR UPDATE;  -- 返回5行,锁定索引范围(20, +∞)

-- 事务B:尝试插入,被阻塞(等待事务A释放锁)
INSERT INTO user (name, age) VALUES ('新用户', 25);  -- 阻塞!

-- 事务A:提交后,事务B才能继续
COMMIT;

4. SERIALIZABLE(串行化)

核心规则:最高隔离级别,事务以串行方式执行,完全避免并发问题。

核心机制:InnoDB的SERIALIZABLE级别会自动将所有普通SELECT转换为SELECT ... FOR SHARE(共享锁)。这意味着:

  • 多个事务可以同时读取同一行(共享锁兼容)
  • 任何事务都不能修改被其他事务读取的行(共享锁与排他锁互斥)
  • 从而实现了事务的完全串行化执行

示例

-- 事务A:开启事务,自动加共享锁
BEGIN;
SELECT * FROM account WHERE id = 1;  -- 自动转换为 SELECT ... FOR SHARE

-- 事务B:尝试更新同一行,被阻塞(共享锁与排他锁互斥)
UPDATE account SET balance = 500 WHERE id = 1;  -- 阻塞,等待事务A释放锁

-- 事务A:提交后,事务B才能继续
COMMIT;  -- 事务B此时才能执行

缺点:并发性能极差,容易出现大量锁等待和死锁。


五、MySQL中的设置

查看当前隔离级别

-- MySQL 8.0+
SELECT @@global.transaction_isolation;
SELECT @@session.transaction_isolation;
SELECT @@transaction_isolation;

-- MySQL 5.7及更早版本(兼容写法)
SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;

设置隔离级别

-- MySQL 8.0+
SET GLOBAL transaction_isolation = 'REPEATABLE-READ';
SET SESSION transaction_isolation = 'READ-COMMITTED';
SET transaction_isolation = 'SERIALIZABLE';

-- MySQL 5.7及更早版本(兼容写法)
SET GLOBAL tx_isolation = 'REPEATABLE-READ';
SET SESSION tx_isolation = 'READ-COMMITTED';
SET tx_isolation = 'SERIALIZABLE';

启动参数设置

# my.cnf 或 my.ini
[mysqld]
transaction-isolation = REPEATABLE-READ

六、隔离级别对比总结

隔离级别 性能 一致性 并发问题 核心实现机制(InnoDB)
READ UNCOMMITTED 最高 最差 脏读、不可重复读、幻读
READ COMMITTED 较高 较差 不可重复读、幻读 语句级MVCC
REPEATABLE READ 中等 较好 幻读(InnoDB通过MVCC+Next-Key Lock共同避免) 事务级MVCC(快照读)+ Next-Key Lock(当前读)
SERIALIZABLE 最低 最好 无(完全串行化) 所有读加共享锁,完全串行化

七、实际选择建议

  • MySQL默认REPEATABLE-READ:适合大多数业务场景,InnoDB通过MVCC和锁机制在保证一定并发性的同时防止脏读、不可重复读和幻读。大多数互联网业务使用MySQL默认的RR级别即可

  • 金融、账务类系统:可考虑SERIALIZABLE或使用分布式锁确保强一致性。只有对一致性要求极高的场景(如银行核心账务)才考虑SERIALIZABLE

  • 高并发查询类系统:可考虑READ-COMMITTED,减少锁竞争提升性能。

  • 测试环境想重现并发问题:使用READ-UNCOMMITTED。

八、注意事项

  1. 隔离级别不是越高越好:应根据业务场景选择合适的隔离级别,避免过度加锁导致性能问题。

  2. MySQL RR级别防止幻读:通过MVCC(快照读)+ Next-Key Lock(当前读)共同实现,比标准RR更严格。

  3. 长事务风险:高隔离级别下,长事务会持有大量锁,影响并发性能,应尽量避免。在InnoDB RR级别下,长事务还会导致undo log无法清理,因为MVCC需要保留旧版本数据供长事务的快照读使用,长事务运行时间越长,积累的undo log就越多,可能导致磁盘空间暴涨,甚至影响数据库性能

  4. 分布式事务:单库隔离级别不适用于跨库场景,需使用分布式事务协议(如XA)或应用层协调。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 事务隔离级别(图文详解) 什么是事务? 事务是逻辑上的一组操作,要么都执行,要么都不执行。 事务最经典也经常被拿出...
    timothyue1阅读 265评论 0 1
  • MySQL事务隔离级别是数据库为解决并发事务间数据一致性问题而设计的核心机制,其核心作用是控制一个事务对另一个事务...
    高文杰_XY阅读 40评论 0 1
  • 首先说一下ACID四大特性: 四大特性 原子性事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行...
    Cenuon_阅读 903评论 0 0
  • 一、MySQL 事务 MySQL 事务指在InnoDB引擎下,MyISAM引擎不支持事务的。 数据库事务指的是一组...
    追梦人胜胜阅读 330评论 0 0
  • 数据库事务 数据库事务(transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执...
    _老七阅读 344评论 0 0

友情链接更多精彩内容