数据库事务的隔离级别是用来控制并发事务之间可见性的重要概念。隔离的目的是让并发执行的事务看起来像是按某种顺序依次执行的,从而避免并发可能导致的问题。
标准 SQL 定义了四种隔离级别,从最强到最弱依次是:
-
可串行化 (SERIALIZABLE):
- 这是最高的隔离级别。
- 它保证并发执行的事务产生的结果与它们按 某个 顺序串行执行(即一个接一个完全执行)的结果完全相同。
- 在这个级别下,并发事务之间不会出现任何问题,包括脏读(Dirty Read)、不可重复读(Non-repeatable Read)和幻读(Phantom Read)。
- 教材中 Sally 查询价格而 Joe 修改价格的例子,如果 Sally 的查询和 Joe 的修改都被定义为可串行化的事务,那么 Sally 要么看到 Joe 修改之前的所有价格(MAX=3.00, MIN=2.50),要么看到修改之后的价格(MAX=3.50, MIN=3.50),但不会看到 MAX < MIN 的不一致情况。
-
可重复读 (REPEATABLE READ):
- 这个级别低于可串行化。
- 它保证在同一事务内,如果多次读取同一个数据项,所得到的值都是一致的。也就是说,一个事务在读数据时,其他事务不能修改这个数据。
- 它防止了脏读和不可重复读。
- 但是,它允许幻读。幻读是指在一个事务中,多次执行同一查询条件,第二次查询会看到第一次查询没有看到的行(这些新行是其他事务在第一次查询后插入并提交的)。
- 在教材的例子中,如果 Sally 的事务隔离级别是可重复读,当她执行 (min) 查询时,即使 Joe 的修改事务(del 后 ins)已经提交,(min) 查询仍然必须看到 (max) 查询时存在的旧价格 (2.50, 3.00),同时可能也会看到新价格 (3.50),但保证了之前看到的数据仍然可见。不过,如果 Joe 在 Sally 两次查询之间插入了新的价格行,Sally 的第二次查询可能会看到这些新插入的行(幻读)。
-
读已提交 (READ COMMITTED):
- 这个级别低于可重复读。
- 它保证一个事务只能读取已经被其他事务提交的数据。
- 它防止了脏读。
- 但是,它允许不可重复读(因为在她两次读取同一数据项之间,另一个事务可能已经修改并提交了该数据)和幻读。
- 在教材例子中,如果 Sally 的隔离级别是读已提交,并且执行顺序是 (max)(del)(ins)(min),只要 Joe 的修改(del 和 ins)在 Sally 执行 (min) 查询之前提交,Sally 就会看到修改后的价格 3.50,导致 MAX < MIN 的不一致情况出现。
-
读未提交 (READ UNCOMMITTED):
- 这是最低的隔离级别。
- 它允许一个事务读取尚未提交的其他事务的数据(即脏读)。
- 它不防止任何并发问题:允许脏读、不可重复读和幻读。
- 在教材例子中,如果 Sally 的隔离级别是读未提交,她甚至可能在 Joe 的事务执行完 (ins) 但还未提交或回滚之前,就看到价格 3.50。如果 Joe 随后回滚了他的事务,那么 Sally 看到的价格 3.50 实际上从未真正存在于数据库中。
选择合适的隔离级别需要在数据一致性(由更高的隔离级别提供)和并发性能(由更低的隔离级别提供,因为锁的范围或持续时间更小)之间进行权衡。大多数数据库系统的默认隔离级别通常是读已提交。