MySQL 事务的隔离级别

MySQL 事务的隔离级别定义了多个事务并发执行时,如何防止相互影响。隔离级别越高,数据一致性越强,但并发性能可能降低。


四种事务隔离级别

MySQL 提供 4 种事务隔离级别(从低到高):

隔离级别 脏读(Dirty Read) 不可重复读(Non-repeatable Read) 幻读(Phantom Read)
1. 读未提交(Read Uncommitted) ❌ 可能发生 ❌ 可能发生 ❌ 可能发生
2. 读已提交(Read Committed) ✅ 不会发生 ❌ 可能发生 ❌ 可能发生
3. 可重复读(Repeatable Read)(MySQL 默认 ✅ 不会发生 ✅ 不会发生 ❌ 可能发生(InnoDB 解决)
4. 可串行化(Serializable) ✅ 不会发生 ✅ 不会发生 ✅ 不会发生

✅:不会发生(已解决),❌:可能发生(未解决)


1. 读未提交(Read Uncommitted)

特点

  • 事务可以读取 其他事务未提交的数据,可能读到“脏数据”(Dirty Read)。
  • 并发性能最高,但数据一致性最差。

示例(脏读问题):

-- 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; -- 原始值

适用场景

  • 基本不用,因为数据一致性较差。

2. 读已提交(Read Committed)

特点

  • 只能读取已提交的数据,解决了“脏读”问题。
  • 但同一事务内多次查询可能会得到 不同的数据不可重复读)。

示例(不可重复读问题):

-- 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

适用场景

  • 大部分数据库(如 SQL Server、Oracle)默认使用
  • 适合 高并发读写 的场景,如 银行账户查询(不影响一致性)。

3. 可重复读(Repeatable Read)MySQL 默认

特点

  • 同一事务内,多次读取相同数据,结果一致(防止“不可重复读”)。
  • 但可能遇到 幻读(Phantom Read)。

示例(幻读问题):

-- 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 解决方案:

  • InnoDB 通过“间隙锁(Next-Key Lock)”避免幻读
  • 大部分情况下,MySQL 可重复读 ≈ 可串行化,但性能更高。

适用场景

  • 默认推荐,适用于大多数业务场景,如 订单处理、银行转账

4. 可串行化(Serializable)

特点

  • 最高级别隔离,事务串行执行,所有事务 加表级锁,防止所有并发问题(脏读、不可重复读、幻读)。
  • 并发性能最低,通常只用于金融等高一致性场景

示例:

-- 在 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 解决) 订单系统、电商平台
可串行化 完全隔离,事务串行化 性能最低 银行、金融系统

推荐使用:

  • 大多数 MySQL 业务,默认使用 REPEATABLE READ(性能与一致性兼顾)。
  • 高并发系统,选择 READ COMMITTED(避免长事务锁表)。
  • 金融、账务系统,使用 SERIALIZABLE(防止并发数据错误)。

理解事务隔离级别,合理选择,优化数据库性能!

你可能感兴趣的:(java,mysql,事务)