← 返回题目列表

PostgreSQL 事务隔离级别有哪些?和 MySQL 有什么不同?

高频 中等 第 10 / 31 题 更新于 2026/07/28
PostgreSQL事务隔离级别MVCC并发

简化版

PostgreSQL 支持 Read Uncommitted、Read Committed、Repeatable Read、Serializable 四种 SQL 标准隔离级别,但 Read Uncommitted 在 PostgreSQL 中表现得和 Read Committed 一样,不会读到脏数据。默认隔离级别是 Read Committed。PostgreSQL 的 Repeatable Read 基于快照,通常不会出现不可重复读和幻读;Serializable 则进一步提供可串行化语义,可能因并发冲突让事务失败重试。

详细版

PostgreSQL 隔离级别可以这样理解:

隔离级别PostgreSQL 行为重点常见面试点
Read Uncommitted实际表现为 Read CommittedPostgreSQL 不允许脏读
Read Committed每条语句看到一个新的已提交快照默认隔离级别
Repeatable Read一个事务内使用稳定快照避免不可重复读和幻读
Serializable结果等价于某种串行执行可能出现序列化失败,需要重试

和 MySQL InnoDB 常见差异在于:MySQL 默认是 Repeatable Read,而 PostgreSQL 默认是 Read Committed;PostgreSQL 的 Read Uncommitted 不会真正脏读;PostgreSQL Serializable 是更强的可串行化控制,不是简单依赖锁把所有事务排队。

完整版教学

一、隔离级别解决什么问题

事务隔离级别用来控制并发事务之间能看到什么数据。常见异常包括:

  • 脏读:读到别人还没提交的数据;
  • 不可重复读:同一事务里两次读同一行,结果不同;
  • 幻读:同一事务里两次按条件查询,结果集合变化;
  • 写偏斜:多个事务各自检查条件后写入不同数据,最终破坏整体约束。

不同数据库对 SQL 标准隔离级别的实现细节不完全一样,面试时不能只背名字,要结合具体数据库说明。

二、Read Committed 是 PostgreSQL 默认级别

Read Committed 下,每条 SQL 语句开始时会看到一个新的已提交快照。

例如一个事务里执行两次查询:

BEGIN;
SELECT stock FROM product WHERE id = 1;
SELECT stock FROM product WHERE id = 1;
COMMIT;

如果两次查询之间有其他事务提交了更新,第二次查询可能看到新值。这符合 Read Committed 的语义。

它适合大多数普通业务写入,因为并发性好,锁冲突相对少。但如果业务要求“整个事务期间读到的数据必须稳定”,就要考虑 Repeatable Read 或显式加锁。

三、Repeatable Read 使用事务级快照

Repeatable Read 下,事务开始后会使用稳定快照。事务内重复查询同一条件,通常看到的是同一批快照数据。

这对报表统计、批量校验、复杂读写逻辑很有用。不过要注意,它不是所有并发问题的万能解。某些跨多行约束、多个事务同时基于旧快照做判断的场景,仍可能出现写偏斜。

例如两个医生值班的例子:每个事务都看到还有另一个人在值班,于是各自把自己设置为休息,最终可能没人值班。如果数据库约束没有表达这个规则,Repeatable Read 未必能阻止。

四、Serializable 提供更强一致性

Serializable 要求并发事务最终结果等价于某种串行执行。PostgreSQL 会检测可能破坏串行化的并发模式,一旦发现无法安全排序,可能让其中一个事务失败。

应用层要能处理类似“could not serialize access”的错误,并重试整个事务。Serializable 的重点不是“不会失败”,而是“失败后重试可以得到安全结果”。

适合使用 Serializable 的场景包括:

  • 强一致性金额转账;
  • 库存、额度、名额等严格约束;
  • 复杂条件校验后写入;
  • 很难用单条 SQL 或约束表达业务不变量的场景。

五、和 MySQL 的常见比较

面试常见追问是 PostgreSQL 和 MySQL 的差异:

  • PostgreSQL 默认 Read Committed,MySQL InnoDB 默认 Repeatable Read;
  • PostgreSQL 的 Read Uncommitted 不会产生脏读;
  • PostgreSQL Repeatable Read 基于事务快照;
  • PostgreSQL Serializable 更强调可串行化检测和失败重试;
  • MySQL InnoDB 在 Repeatable Read 下还会结合 next-key lock 处理一些范围写冲突。

比较时不要说谁绝对更好,而要说隔离语义、锁策略、默认配置和业务使用方式不同。

六、常见误区与追问

隔离级别快照特点主要提醒
Read Committed每条语句新快照默认级别,可能不可重复读
Repeatable Read事务级稳定快照仍要关注写偏斜
Serializable可串行化检测失败后重试是设计的一部分

易错点:PostgreSQL 的 Read Uncommitted 不会脏读;Serializable 也不是“永不出错”,而是通过检测冲突让事务失败并要求应用重试。

一个写偏斜例子:值班表要求至少 1 名医生在线,医生 A 和 B 两个事务都在 Repeatable Read 下看到“还有对方在线”,于是分别把自己设为离线。两个事务修改的是不同行,单行冲突不明显,但最终约束被破坏。这个问题要靠 Serializable、显式锁、约束建模或单条条件更新来处理。

  • 误区:Read Uncommitted 在 PostgreSQL 会读到脏数据。 PostgreSQL 中它实际表现为 Read Committed,不允许脏读。
  • 误区:Repeatable Read 能解决所有并发异常。 它能提供稳定快照,但某些跨行约束仍可能出现写偏斜。
  • 误区:Serializable 就是把所有事务串行排队。 PostgreSQL 会做可串行化检测,发现危险并发模式时让事务失败重试。
  • 追问:PostgreSQL 默认隔离级别是什么? 默认是 Read Committed,和 MySQL InnoDB 默认 Repeatable Read 不同。
  • 追问:Serializable 失败怎么处理? 捕获序列化失败错误,回滚并重试整个事务,不能只重试最后一条 SQL。
  • 追问:什么时候不用提升隔离级别也能解决? 能用唯一约束、CHECK、行锁、条件更新或单条原子 SQL 表达的不变量,优先用这些更明确的手段。

七、加强记忆

PostgreSQL 隔离级别的记忆线是:默认 Read Committed,每条语句一个快照;Repeatable Read,一个事务一个稳定快照;Serializable,保证可串行化但要准备重试;Read Uncommitted 在 PostgreSQL 中不会脏读。