↑↓ 选择 ↵ 打开 ⌫ 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1
历史版本PostgreSQL 7.3 已于 2007 年 11 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本。

9.4. 应用级别的数据一致性检查 #

由于 PostgreSQL 中的读操作不加锁(无论事务隔离级别如何),一个事务读取的数据仍可能被另一个并发事务覆盖。换句话说,某行被 SELECT 返回,并不意味着该行在返回的那一刻(即当前查询开始之后的某个时刻)仍然是当前的。该行可能已经被一个在本事务开始之后提交的已提交事务修改或删除。即使该行“现在”仍然有效,它也可能在当前事务提交或回滚之前被更改或删除。

换个角度想,每个事务看到的都是数据库内容的一个快照,而并发执行的事务完全可能看到不同的快照。因此“现在”这个概念本身就很可疑。 如果客户端应用彼此隔离,这通常不是什么大问题;但如果客户端能通过数据库之外的渠道通信,就可能引发严重的混乱。

要确保某一行当前仍然有效,并保护它不受并发更新影响,就必须使用 SELECT FOR UPDATE 或适当的 LOCK TABLE 语句。( SELECT FOR UPDATE 只锁定返回的行以防止并发更新,而 LOCK TABLE 会锁住整张表。)从其他环境向 PostgreSQL 移植应用时,应当考虑这一点。

注意

在 6.5 版之前,PostgreSQL 使用的是读锁,因此从早于 6.5 的 PostgreSQL 版本升级时,上述考虑同样相关。

在 MVCC 之下,全局有效性检查需要格外用心。例如,一个银行应用可能想检查一张表中所有贷方金额之和等于另一张表中借方金额之和,而两张表都在被活跃地更新。在读已提交模式下,比较两条先后执行的 SELECT SUM(...) 命令的结果并不可靠,因为第二条查询很可能把第一条查询未计入的事务的结果包含进来。在单个可串行化事务中做两次求和,可以准确反映该可串行化事务开始之前已提交事务的效果——但人们完全有理由怀疑,等到结果交付时它是否仍然有效。如果可串行化事务在尝试做一致性检查之前自己已经做了某些更改,这个检查的有用性就更值得商榷了,因为此时它包含的是事务开始后一部分而非全部更改。在这种情况下,谨慎的人可能希望把检查所需的所有表都锁住,以获得关于当前现实无可争议的图景。 SHARE 模式(或更高模式)的锁保证被锁表中没有未提交的更改,当前事务自己的更改除外。

还要注意,如果依靠显式锁来防止并发更改,就应当使用读已提交模式;或者在可串行化模式下小心确保在执行查询之前先取得锁。在可串行化事务中取得的显式锁保证没有其他正在修改该表的事务还在运行——但如果事务看到的快照早于取得锁的时刻,它也可能早于表中一些现已提交的更改。可串行化事务的快照实际上是在其第一条查询 (SELECT、INSERT、 UPDATE 或 DELETE)开始时冻结的,因此完全可以在快照冻结之前先取得显式锁。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。