MySQL 事务的隔离级别定义了多个事务并发执行时,如何防止相互影响。隔离级别越高,数据一致性越强,但并发性能可能降低。
MySQL 提供 4 种事务隔离级别(从低到高):
隔离级别 | 脏读(Dirty Read) | 不可重复读(Non-repeatable Read) | 幻读(Phantom Read) |
---|---|---|---|
1. 读未提交(Read Uncommitted) | ❌ 可能发生 | ❌ 可能发生 | ❌ 可能发生 |
2. 读已提交(Read Committed) | ✅ 不会发生 | ❌ 可能发生 | ❌ 可能发生 |
3. 可重复读(Repeatable Read)(MySQL 默认) | ✅ 不会发生 | ✅ 不会发生 | ❌ 可能发生(InnoDB 解决) |
4. 可串行化(Serializable) | ✅ 不会发生 | ✅ 不会发生 | ✅ 不会发生 |
✅:不会发生(已解决),❌:可能发生(未解决)
特点:
示例(脏读问题):
-- Session 1: 事务A 修改但未提交
START TRANSACTION;
UPDATE accounts SET balance = 5000 WHERE id = 1;
-- 此时事务A未提交
-- Session 2: 事务B 读取数据,看到未提交的数据(脏读)
SELECT balance FROM accounts WHERE id = 1; -- 5000(但事务A可能回滚)
-- Session 1: 事务A 回滚
ROLLBACK;
-- Session 2: 事务B 重新查询,数据变回原来的(数据不一致)
SELECT balance FROM accounts WHERE id = 1; -- 原始值
适用场景:
特点:
示例(不可重复读问题):
-- Session 1: 事务A 开启并查询
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 1; -- 1000
-- Session 2: 事务B 修改并提交
START TRANSACTION;
UPDATE accounts SET balance = 5000 WHERE id = 1;
COMMIT;
-- Session 1: 事务A 重新查询,发现数据已变(不可重复读)
SELECT balance FROM accounts WHERE id = 1; -- 5000
适用场景:
特点:
示例(幻读问题):
-- Session 1: 事务A 查询当前大于 1000 的账户数量
START TRANSACTION;
SELECT COUNT(*) FROM accounts WHERE balance > 1000; -- 5
-- Session 2: 事务B 插入新数据并提交
START TRANSACTION;
INSERT INTO accounts(id, balance) VALUES(10, 2000);
COMMIT;
-- Session 1: 事务A 重新查询,发现数量变了(幻读)
SELECT COUNT(*) FROM accounts WHERE balance > 1000; -- 6
MySQL InnoDB
解决方案:
适用场景:
特点:
示例:
-- 在 Serializable 级别下,所有事务都会加锁,避免并发
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT COUNT(*) FROM accounts WHERE balance > 1000; -- 5
适用场景:
SELECT @@TRANSACTION_ISOLATION;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 读已提交
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- 可重复读(默认)
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- 可串行化
隔离级别 | 保证的事务特性 | 可能出现的问题 | 适用场景 |
---|---|---|---|
读未提交 | 允许读取未提交数据 | 脏读、不可重复读、幻读 | 几乎不用 |
读已提交 | 只能读取已提交数据 | 不可重复读、幻读 | OLTP 系统,适合高并发 |
可重复读(默认) | 事务内数据一致 | 幻读(InnoDB 解决) | 订单系统、电商平台 |
可串行化 | 完全隔离,事务串行化 | 性能最低 | 银行、金融系统 |
推荐使用:
REPEATABLE READ
(性能与一致性兼顾)。READ COMMITTED
(避免长事务锁表)。SERIALIZABLE
(防止并发数据错误)。理解事务隔离级别,合理选择,优化数据库性能!