Mysql的事务隔离级别

167 阅读4分钟

MySQL的事务隔离级别定义了多个并发事务之间的可见性和影响范围,不同级别通过不同的锁机制和并发控制策略来解决数据一致性问题,但也会带来性能与一致性的权衡。以下是各隔离级别的影响及其原理的详细说明:


一、事务隔离级别及其影响

MySQL支持四种标准隔离级别,按隔离强度从低到高排序:

隔离级别脏读(Dirty Read)不可重复读(Non-Repeatable Read)幻读(Phantom Read)默认级别
READ UNCOMMITTED✔️(可能发生)✔️✔️✖️
READ COMMITTED✖️✔️✔️Oracle/SQL Server
REPEATABLE READ✖️✖️✔️(部分场景)MySQL(InnoDB默认)
SERIALIZABLE✖️✖️✖️✖️

二、各隔离级别的影响及原因

1. READ UNCOMMITTED(读未提交)

  • 允许的问题
    • 脏读:事务A可以读取事务B未提交的数据。
    • 不可重复读:事务A多次读取同一数据,可能因事务B的提交而结果不同。
    • 幻读:事务A读取的范围数据可能因事务B插入新数据而改变。
  • 原因
    • 无锁机制:事务直接读取内存中的最新数据(包括未提交的修改)。
    • 不隔离修改:完全牺牲一致性换取最高并发性能。

2. READ COMMITTED(读已提交)

  • 允许的问题
    • 不可重复读:事务A两次读取同一数据可能不同(事务B提交了修改)。
    • 幻读:事务A两次范围查询结果可能不同(事务B插入了新数据)。
  • 解决脏读的原理
    • MVCC(多版本并发控制)
      • 每个事务读取的是已提交的快照版本(通过ReadView机制)。
      • 未提交的修改对其他事务不可见。
  • 遗留问题的原因
    • 快照更新:每次查询生成新的ReadView,可能看到其他事务已提交的新数据。

3. REPEATABLE READ(可重复读)

  • 允许的问题
    • 幻读(部分场景):事务A范围查询可能因事务B插入新数据而出现“幻行”。
  • 解决不可重复读的原理
    • MVCC + 一致性快照
      • 事务首次读取时生成ReadView,后续读取沿用同一快照版本。
      • 其他事务的提交不会影响当前事务的可见性。
  • 幻读的残留原因
    • 当前读(Current Read)
      • 若事务A执行SELECT ... FOR UPDATEUPDATE语句,会读取最新数据并加锁,可能发现新插入的行。
    • 间隙锁(Gap Lock)
      • InnoDB通过间隙锁锁定范围间隙,阻止其他事务插入新数据,但仅在使用当前读时生效。

4. SERIALIZABLE(串行化)

  • 解决的问题
    • 所有并发问题(脏读、不可重复读、幻读)。
  • 原理
    • 完全串行执行
      • 所有SELECT语句隐式转换为SELECT ... FOR SHARE,对读取的行加共享锁。
      • 写操作加排他锁,严格禁止并发修改。
  • 代价
    • 极低并发性能:锁竞争激烈,仅适合低并发场景。

三、InnoDB如何解决幻读?

在默认的REPEATABLE READ级别下,InnoDB通过以下机制减少幻读:

  1. MVCC快照读
    • 普通SELECT使用一致性快照,其他事务的插入不影响当前事务的可见性。
  1. 间隙锁(Gap Lock)
    • 在执行UPDATEDELETESELECT ... FOR UPDATE时,InnoDB对索引记录的间隙加锁,阻止其他事务在范围内插入新数据。
    • 例如,WHERE id > 100的查询会锁住id > 100的间隙,防止插入id=101的新记录。

四、隔离级别选择的权衡

隔离级别一致性并发性能适用场景
READ UNCOMMITTED最低最高几乎不用,仅测试场景
READ COMMITTED较低较高高并发读,允许短暂不一致
REPEATABLE READ较高中等多数业务场景(MySQL默认)
SERIALIZABLE最高最低金融交易等强一致性需求

五、示例验证

幻读在REPEATABLE READ下的表现

-- 事务A
BEGIN;
SELECT * FROM users WHERE age > 20; -- 快照读,返回2条记录

-- 事务B
INSERT INTO users (name, age) VALUES ('John', 25); -- 提交

-- 事务A
SELECT * FROM users WHERE age > 20; -- 仍返回2条(快照读)
UPDATE users SET name = 'test' WHERE age > 20; -- 当前读,发现事务B插入的行,导致幻读!
COMMIT;

总结

  • 低隔离级别(如READ UNCOMMITTED) :性能高,但数据一致性差,适合对数据准确性要求极低的场景。
  • 默认级别(REPEATABLE READ) :通过MVCC和间隙锁平衡一致性与性能,适合大多数业务。
  • 高隔离级别(SERIALIZABLE) :强一致性,但并发性能差,仅用于特殊场景。

理解隔离级别的实现原理(如MVCC、锁机制)和业务需求,是合理选择隔离级别的关键。