四种事务隔离及别

事务隔离级别是数据库管理系统 (DBMS) 中用来控制并发访问时数据一致性的一种机制。不同的隔离级别可以提供不同程度的数据一致性和并发性能平衡。

事务的基本要素(ACID)

  • 原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
  • 一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如 A 向 B 转账,不可能 A 扣了钱,B 却没收到。
  • 隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如 A 正在从一张银行卡中取钱,在 A 取钱的过程结束前,B 不能向这张卡转账。
  • 持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

事务的并发问题

  • 脏读:事务 A 读取了事务 B 更新的数据,然后 B 回滚操作,那么 A 读取到的数据是脏数据
  • 不可重复读:事务 A 多次读取同一数据,事务 B 在事务 A 多次读取的过程中,对数据作了更新并提交,导致事务 A 多次读取同一数据时,结果 不一致。
  • 幻读:系统管理员 A 将数据库中所有学生的成绩从具体分数改为 ABCDE 等级,但是系统管理员 B 就在这个时候插入了一条具体分数的记录,当系统管理员 A 改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

四种事务隔离级别

SQL 标准定义了四种事务隔离级别,每种级别在并发场景下会表现出不同的行为。这四种隔离级别从低到高分别是:

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
读已提交(read-committed)
可重复读(repeatable-read)
串行化(serializable)

1. 读未提交(Read Uncommitted)

  • 特点: 允许一个事务读取另一个未提交事务所修改的数据。
  • 问题: 可能导致 脏读(Dirty Read)。即,一个事务可以读到另一个事务尚未提交的数据,如果该事务回滚,读到的数据就是无效的。
  • 应用场景: 很少使用,通常用于不需要严格数据一致性的场景,因为它提供的隔离性最低。

2. 读已提交(Read Committed)

  • 特点: 只允许事务读取已提交的数据。即,一个事务只能读取到其他事务已经提交的数据。
  • 问题: 可能导致 不可重复读(Non-repeatable Read)。即,在同一个事务中,多次读取同一行数据,结果可能不同,因为其他事务可能在期间修改并提交了该数据。
  • 应用场景: 是许多数据库的默认隔离级别(如 Oracle)。适用于不需要数据完全一致但希望避免脏读的场景。

3. 可重复读(Repeatable Read)

  • 特点: 确保在同一事务中,多次读取同一行数据的结果是一致的。事务开始后,其他事务的修改在当前事务中不可见。
  • 问题: 可能导致 幻读(Phantom Read)。即,一个事务在读取某个条件下的行时,如果另一个事务插入了符合条件的新行,前一个事务再次查询时会看到 “幻影” 行。
  • 应用场景: 常用于需要避免不可重复读的场景,MySQL 默认使用此隔离级别。

4. 可串行化(Serializable)

  • 特点: 是最高级别的隔离,确保事务完全串行化执行,仿佛所有事务是一个接一个顺序执行的,而非并发执行的。
  • 问题: 解决了幻读问题,但代价是并发性能显著降低,可能导致大量的锁竞争,降低系统的并发能力。
  • 应用场景: 用于数据一致性要求非常高的场景,但通常代价较高。

总结

  • 读未提交:最低级别,可能发生脏读。
  • 读已提交:避免脏读,但可能发生不可重复读。
  • 可重复读:避免脏读和不可重复读,但可能发生幻读。
  • 可串行化:最高级别,避免所有并发问题,但性能开销最大。

每种隔离级别在不同的业务需求下有不同的适用场景,选择合适的隔离级别是设计数据库事务的重要考量。