当多个事务同时在数据库中运行时,并发控制是一种用于维持一致性与隔离性的技术,一致性与隔离性是 ACID 的两个属性。ACID 指数据库事务正确执行的四个基本要素,包含原子性(Atomicity)​、一致性(Consistency)​、隔离性(Isolation)​、持久性(Durability)​。

PostgreSQL 为开发人员提供了一套丰富的工具来管理对数据的并发访问。

在内部,数据一致性是通过使用多版本模型(多版本并发控制,Multiversion Concurrency Control, MVCC)来维护的。这意味着,无论底层数据的当前状态如何,每条 SQL 语句都会看到一个与前段时间一样的数据快照(数据库版本)。这可以防止语句查看并发事务对同一数据行执行更新所产生的不一致数据,从而为每个数据库会话提供事务隔离。

MVCC 通过避开传统数据库系统的锁方案,最大限度地减少了锁的争抢,以便在多用户环境中达到更好的表现。

使用并发控制而不是锁的 MVCC 模型的主要有点是:在 MVCC 中,为查询(读取)数据而获取的锁与为写入数据而获取到的锁不冲突,因此读取从来不会阻碍写入,写入也从来不会阻碍读取。PostgreSQL 即使在使用可串行化快照隔离(SSI)来提供最严格级别的事务隔离时,也能保证这一点。

PostgreSQL 中还提供了表级和行级锁功能,用于那些不需要进行完全的事务隔离并且更喜欢显示管理特定冲突点的应用程序。然而,正确使用 MVCC 通常会提供比锁更好的性能。此外,应用程序中定义的咨询锁提供了一种获取不会绑定到单个事务的锁的机制。

并发控制技术

从宽泛的意义上来讲,有三种并发控制技术,分别是:

  • 多版本并发控制(Multi-Version Concurrency Control,MVCC)​
  • 严格两阶段锁定(Strict Two-Phase Locking,S2PL)
  • 乐观并发控制(Optimistic Concurrency Control,OCC)

每种技术都有多种变体。在 MVCC 中,每个写操作都会创建一个新版本的数据项,并保留其旧版本。当事务读取数据对象时,系统会选择其中的一个版本,通过这种方式来确保各个事务间相互隔离。MVCC 的主要优势在于“读不会阻塞写,写也不会阻塞读”​,相反的例子是,基于 S2PL 的系统在写操作发生时会阻塞相应对象上的读操作,因为写入者获取了对象上的排他锁。PostgreSQL 和一些关系型数据库使用一种 MVCC 的变体,叫作快照隔离(Snapshot Isolation,SI)​。

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

另外,PostgreSQL 对 DML(SELECT、UPDATE、INSERT、DELETE 等命令)使用 SSI,对 DDL (CREATE TABLE 等命令)使用 2PL。

相关链接

数据库事务隔离级别 - z2huo

PostgreSQL: Documentation: 16: Chapter 13. Concurrency Control

[[事务隔离级别]]

OB tags

#PostgreSQL #事务