跳到主要内容

并发与事务隔离

一、并发带来的问题​

1.丢失更新​

定义:两个事务同时读取同一数据,然后分别基于原始值进行修改,后提交的事务覆盖了先提交的修改。

典型场景:计数器、余额扣减。

示例:

T1 读 A=100;T2 读 A=100;T1 更新 A=200 并提交;T2 更新 A=300 并提交 → 最终 A=300,T1 的更新丢失。

阻止:提高隔离级别至 可重复读 或可串行化,并加锁

2.脏读​

定义:一个事务读取了另一个未提交事务写入的数据。如果后来那个事务回滚,读到的数据就是无效的。

示例:

T1 修改 A=200(未提交);T2 读取 A=200;T1 回滚 → T2 读到了脏数据。

危害:数据不一致,可能导致错误决策。

阻止:隔离级别 ≥ 读已提交(READ COMMITTED)。

3.不可重复读​

定义:同一事务内,两次读取同一行数据,期间另一个事务修改并提交了该行,导致两次结果不同。

示例:

T1 读 A=100;T2 修改 A=200 并提交;T1 再次读 A=200 → 两次结果不一致。

阻止:隔离级别 ≥ 可重复读(REPEATABLE READ)

4.幻读​

定义:同一事务内,两次执行同一个范围查询,期间另一个事务插入/删除满足条件的新行,导致第二次查询返回不同的行集。

示例:

T1 查询 WHERE age=20 得到 3 行;T2 插入一条 age=20 的新行并提交;T1 再次查询得到 4 行 → 出现"幻影"行。

区别不可重复读:

  • 不可重复读:同一行内容被修改。

  • 幻读:行集合发生变化(插入/删除)。

阻止:隔离级别 可串行化(SERIALIZABLE)


二、事务隔离级别​

1.读未提交(Read Uncommitted)​

  • 允许一个事务读取另一个未提交事务的修改。

  • 解决的问题:几乎不解决任何并发问题。

  • 可能存在的异常:脏读、不可重复读、幻读、丢失更新都可能发生。

  • 适用场景:对数据一致性要求极低,但需要极高并发读的场景(极少使用)

2.读已提交(Read Committed)​

  • 只能读取已经提交的数据,不允许读取未提交的修改。

  • 解决的问题:脏读。

  • 仍可能存在的异常:不可重复读、幻读、丢失更新(后两种在某些实现中可能部分避免,但标准下仍可能)。

  • 注意:这是很多数据库(如 PostgreSQL、Oracle)的默认隔离级别。

3.可重复读(Repeatable Read)​

  • 保证在同一事务内,多次读取同一行数据的结果是一致的。事务开始后,其他事务不能修改当前事务已读取的行(通常通过行锁或快照实现)。

  • 解决的问题:脏读、不可重复读。

  • 仍可能存在的异常:幻读(标准 SQL 下允许幻读;但部分数据库如 MySQL InnoDB 通过间隙锁也在该级别下避免了幻读)。丢失更新在标准中也不会发生(因为可重复读通常意味着读取时加锁或使用快照,更新时加锁)。

  • 注意:MySQL InnoDB 的默认隔离级别。

4.可串行化(Serializable)​

  • 最高的隔离级别,强制事务串行执行(或通过某种机制达到与串行执行等价的效果,如两阶段锁或 MVCC 加冲突检测)。所有并发事务的效果等同于按某个顺序依次执行。

  • 解决的问题:脏读、不可重复读、幻读、丢失更新全部避免。

  • 代价:并发性能最低,可能产生大量锁等待或超时。


三、各事务隔离级别优缺点以及选择​

1.读未提交​

  • 优点:并发性能最高,无锁开销。

  • 缺点:允许脏读、不可重复读、幻读,数据一致性最差。

  • 适用:几乎不用,仅适用于对数据一致性无任何要求的特殊场景。

2.读已提交​

  • 优点:解决脏读,并发性能高(读不加锁),是 Oracle、PostgreSQL 的默认级别。

  • 缺点:仍可能出现不可重复读、幻读及丢失更新。

  • 适用:大多数在线事务处理系统(OLTP),如用户发帖、点赞、订单查询等。

3.可重复读​

  • 优点:解决脏读和不可重复读;在 MySQL InnoDB 中通过间隙锁还能防止幻读。一致性较高。

  • 缺点:间隙锁可能增加锁冲突和死锁概率,并发性能低于读已提交。

  • 适用:需要同一事务内多次读取结果一致的场景(如财务报表),以及 MySQL 的默认推荐。

4.可串行化​

  • 优点:解决所有并发问题(脏读、不可重复读、幻读、丢失更新),一致性最高。

  • 缺点:并发性能最低,大量锁等待或超时。

  • 适用:极少数对一致性要求极高且并发很低的场景(如金融短事务)。

总结​

  • 读未提交:脏读 ✔、不可重复读 ✔、幻读 ✔、丢失更新 ✔

  • 读已提交:脏读 ✘、不可重复读 ✔、幻读 ✔、丢失更新 ✔(标准下)

  • 可重复读:脏读 ✘、不可重复读 ✘、幻读 ✔(标准下)、丢失更新 ✘(标准下)

  • 可串行化:全部 ✘

注:"✔"表示可能发生,"✘"表示该级别已解决此问题。实际数据库实现可能因具体机制(如 MVCC、间隙锁)而有所增强,例如 MySQL InnoDB 的 REPEATABLE READ 也能防止幻读。