MySQL 事务隔离级别详解与应用场景分析_mysql事务隔离级别使用场景
MySQL 事务隔离级别定义了多个事务并发执行时彼此之间的可见性,直接影响数据的一致性和并发性能。MySQL(特别是 InnoDB 引擎)支持以下 四种标准的事务隔离级别,它们从低到高分别是:
🔹 1. Read Uncommitted(读取未提交)
- 特点:一个事务可以读取另一个事务未提交的数据。
- 问题:可能会出现脏读(Dirty Read)。
- 示例:
- 事务 A 修改了一条记录但尚未提交;
- 事务 B 能看到并读取这个未提交的修改;
- 如果 A 回滚,B 得到的是不存在的值。
🔹 2. Read Committed(读取已提交)
- 特点:只能读取已经提交的数据。
- 解决问题:避免了脏读。
- 问题:可能出现不可重复读(Non-repeatable Read)。
- 示例:
- 事务 A 先读取一条数据;
- 事务 B 更新并提交该数据;
- 事务 A 再次读取时,值发生变化。
🔹 3. Repeatable Read(可重复读)(MySQL 默认级别)
- 特点:事务内多次读取同一条记录结果一致。
- 解决问题:避免了脏读和不可重复读。
- 问题:可能出现幻读(Phantom Read)。
- 示例:
- 事务 A 查询某条件下的多条数据;
- 事务 B 插入符合该条件的新记录;
- 事务 A 再次执行相同查询,结果多了一条。
🔹 4. Serializable(可串行化)
- 特点:完全串行化执行,事务间完全隔离。
- 解决问题:避免了幻读。
- 缺点:并发性能最差,锁粒度大,容易造成锁等待。
🔄 各隔离级别对比总结表:
✅ 如何设置隔离级别
查看当前隔离级别:
SELECT @@tx_isolation; -- 旧版本SELECT @@transaction_isolation; -- 新版本
设置当前会话隔离级别:
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
设置全局隔离级别(需重启生效):
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
🔍 一图理解隔离级别的三大问题:
📊 各隔离级别的行为对比表
🔬 详细解释 + 案例举例:
1️⃣ Read Uncommitted(读取未提交)
- 脏读:✅
- 不可重复读:✅
- 幻读:✅
- 适用场景:极少用,几乎没有实际业务需求。
🧪 举例:
-- 事务 ASTART TRANSACTION;UPDATE accounts SET balance = balance - 100 WHERE id = 1;-- 尚未提交-- 事务 B(此时读取了未提交数据)SELECT balance FROM accounts WHERE id = 1;
2️⃣ Read Committed(读取已提交)
- 脏读:❌
- 不可重复读:✅
- 幻读:✅
- 适用场景:多数数据库(如 Oracle)默认,业务允许稍微的并发一致性差异。
🧪 举例:
-- 事务 ASTART TRANSACTION;SELECT salary FROM employees WHERE id = 5; -- 第一次查询:5000-- 事务 BUPDATE employees SET salary = 6000 WHERE id = 5;COMMIT;-- 事务 A(再次查询:返回6000)SELECT salary FROM employees WHERE id = 5;
3️⃣ Repeatable Read(可重复读,MySQL 默认)
- 脏读:❌
- 不可重复读:❌
- 幻读:✅(InnoDB 实际用“间隙锁”解决)
- 适用场景:MySQL 默认,兼顾一致性与并发,适合绝大多数场景。
🧪 举例:
-- 事务 ASTART TRANSACTION;SELECT * FROM orders WHERE user_id = 10;-- 事务 BINSERT INTO orders (user_id, item) VALUES (10, \'Book\');COMMIT;-- 事务 A(再次查询:依旧没有看到新订单)SELECT * FROM orders WHERE user_id = 10;
InnoDB 用“间隙锁(Gap Lock)”防止插入,避免幻读。
4️⃣ Serializable(可串行化)
- 脏读:❌
- 不可重复读:❌
- 幻读:❌
- 适用场景:银行、证券类系统,需要极高数据一致性,牺牲并发性能换一致性保障。
🧪 机制: 每条查询都加锁(共享锁/排他锁),导致事务基本变成串行执行。