PostgreSQL中的事务隔离等级

当多个事务同时在数据库中运行时,并发控制 是一种用于维持一致性隔离性 的技术,一致性与隔离性是ACID的两个属性。

从宽泛的意义上来讲,有三种并发控制技术:多版本并发控制(Multi-version Concurrency Control, MVCC)严格两阶段锁定(Strict Two-Phase Locking, S2PL)乐观并发控制(Optimistic Concurrency Control, OCC) ,每种技术都有多种变体。在MVCC中,每个写操作都会创建一个新版本的数据项,并保留其旧版本。当事务读取数据对象时,系统会选择其中的一个版本,通过这种方式来确保各个事务间相互隔离。 MVCC的主要优势在于“读不会阻塞写,而写也不会阻塞读”,相反的例子是,基于S2PL的系统在写操作发生时会阻塞相应对象上的读操作,因为写入者获取了对象上的排他锁。 PostgreSQL和一些RDBMS使用一种MVCC的变体,名曰快照隔离(Snapshot Isolation,SI)

一些RDBMS(例如Oracle)使用回滚段来实现快照隔离SI。当写入新数据对象时,旧版本对象先被写入回滚段,随后用新对象覆写至数据区域。 PostgreSQL使用更简单的方法:新数据对象被直接插入到相关表页中。读取对象时,PostgreSQL根据可见性检查规则(visibility check rules) ,为每个事务选择合适的对象版本作为响应。

SI中不会出现在ANSI SQL-92标准中定义的三种异常:脏读,不可重复读和幻读。但SI无法实现真正的可串行化,因为在SI中可能会出现串行化异常:例如写偏差(write skew)只读事务偏差(Read-only Transaction Skew) 。需要注意的是:ANSI SQL-92标准中可串行化的定义与现代理论中的定义并不相同 。为了解决这个问题,PostgreSQL从9.1版本之后添加了可串行化快照隔离(SSI,Serializable Snapshot Isolation) ,SSI可以检测串行化异常,并解决这种异常导致的冲突。因此,9.1版本之后的PostgreSQL提供了真正的SERIALIZABLE隔离等级(此外SQL Server也使用SSI,而Oracle仍然使用SI)。

本章包括以下四个部分:

  • 第1部分:第 5.1 ~ 5.3 节。 这一部分介绍了理解后续部分所需的基本信息。 第 5.15.2 节分别描述了事务标识和元组结构。第 5.3 节展示了如何插入,删除和更新元组。
  • 第2部分:第 5.4 ~ 5.6 节。 这一部分说明了实现并发控制机制所需的关键功能。 第 5.45.55.6 节描述了提交日志(clog) ,分别介绍了事务状态,事务快照和可见性检查规则。
  • 第3部分:第 5.7 ~ 5.9 节。 这一部分使用具体的例子来介绍PostgreSQL中的并发控制。 这一部分说明了如何防止ANSI SQL标准中定义的三种异常。第 5.7 节描述了可见性检查,第 5.8 节介绍了如何防止丢失更新,第 5.9 节简要描述了SSI。
  • 第4部分:第 5.10 节。 这一部分描述了并发控制机制持久运行所需的几个维护过程。维护过程主要通过清理过程(vacuum processing) 进行,清理过程将在 第六章 清理过程(VACUUM) 详细阐述。

并发控制包含着很多主题,本章重点介绍PostgreSQL独有的内容。故这里省略了锁模式与死锁处理的内容(相关信息请参阅官方文档)。

PostgreSQL中的事务隔离等级

PostgreSQL实现的事务隔离等级如下表所示:

隔离等级 脏读 不可重复读 幻读 串行化异常
读已提交 不可能 可能 可能 可能
可重复读[1] 不可能 不可能 PG中不可能,见5.7.2小节
但ANSI SQL中可能
可能
可串行化 不可能 不可能 不可能 不可能

[1]:在9.0及更早版本中,该级别被当做SERIALIZABLE,因为它不会出现ANSI SQL-92标准中定义的三种异常。 但9.1版中SSI的实现引入了真正的SERIALIZABLE级别,该级别已被改称为REPEATABLE READ。 PostgreSQL对DML(SELECT, UPDATE, INSERT, DELETE等命令)使用SSI,对DDL(CREATE TABLE等命令)使用2PL。