基于本文回答
0
评论

PostgreSQL 支持哪些事务隔离级别?

知识点图片

PostgreSQL 语法上完全支持 SQL 标准中定义的 4 种事务隔离级别,但在其底层的具体实现上(基于 MVCC 多版本并发控制),具有自己的一些特点。

PostgreSQL 的默认隔离级别是 Read Committed(读已提交)

以下是这 4 种隔离级别在 PostgreSQL 中的具体表现:

1. 读未提交 (Read Uncommitted)

  • SQL 标准: 允许读取未提交的数据(脏读)。
  • PostgreSQL 实现: 虽然你可以在代码中设置这个级别,但在 PostgreSQL 中,它的实际表现和 Read Committed(读已提交)完全一样。因为 PostgreSQL 底层使用的是 MVCC(多版本并发控制),天生不支持且绝对不会发生“脏读”。

2. 读已提交 (Read Committed) —— [默认级别]

  • 特点: 一个事务只能看到在它当前查询(Query)开始之前已经提交的数据。
  • 存在的问题:
    • 允许不可重复读 (Non-repeatable Read):在同一个事务中,如果执行两次相同的 SELECT 查询,期间如果有另一个事务修改并提交了这些数据,两次查询的结果会不一样。
    • 允许幻读 (Phantom Read):在同一个事务中,同样的查询条件,由于其他事务插入或删除了满足条件的数据并提交,后一次查询可能会查出“多出来”或“少掉”的行。

3. 可重复读 (Repeatable Read)

  • 特点: 一个事务只能看到在当前事务(Transaction)开始之前已经提交的数据。在整个事务期间,它看到的是数据库的一个一致性快照。
  • PostgreSQL 的特殊之处: 在 SQL 标准中,可重复读级别是允许发生“幻读”的。但是,在 PostgreSQL 中,该级别下不仅防止了脏读和不可重复读,同时也防止了幻读
  • 注意事项: 当两个并发事务尝试修改同一行数据时,只有一个会成功。后一个尝试修改的事务会报错 (ERROR: could not serialize access due to concurrent update),此时必须由应用程序捕获错误并重试整个事务。

4. 可串行化 (Serializable)

  • 特点: 最严格的隔离级别。它保证并发执行的事务结果,必定与某种依次串行执行(一个接一个执行)的结果完全相同。
  • 实现原理: PostgreSQL 使用了 可串行化快照隔离 (SSI)。它不仅具有 Repeatable Read 的一切特性,还会监控事务之间的读写依赖关系。如果发现可能产生不一致的情况(即序列化异常),它会主动中止其中一个事务并报错 (ERROR: could not serialize access due to read/write dependencies among transactions)。
  • 注意事项: 使用此级别会增加系统开销,并且应用程序必须具备完善的事务重试机制。

现象总结表 (针对 PostgreSQL 实际运行情况)

隔离级别 脏读 (Dirty Read) 不可重复读 (Non-repeatable Read) 幻读 (Phantom Read) 序列化异常 (Serialization Anomaly)
Read Uncommitted ❌ (被PG阻止) ✅ 允许 ✅ 允许 ✅ 允许
Read Committed (默认) ❌ 防止 ✅ 允许 ✅ 允许 ✅ 允许
Repeatable Read ❌ 防止 ❌ 防止 ❌ (被PG阻止) ✅ 允许
Serializable ❌ 防止 ❌ 防止 ❌ 防止 ❌ 防止

注:表中的“被PG阻止”表示虽然 SQL 标准允许该现象,但 PostgreSQL 的底层机制(MVCC)天然消除了这种现象。


如何在 PostgreSQL 中设置隔离级别?

1. 在开启事务时指定(仅对当前事务有效):

sql
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 或者
START TRANSACTION ISOLATION LEVEL SERIALIZABLE;

2. 在事务内部修改(必须在执行任何查询或修改前):

sql
BEGIN;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

3. 设置当前会话(Session)的默认级别:

sql
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED;
右滑查看面试常问