选择 打开 改范围 完整检索页

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
历史版本PostgreSQL 9.0 已于 2015 年 10 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本

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

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

换一种方式来看:每个事务看到的都是数据库内容的一个快照,而并发执行的事务很可能看到不同的快照。因此,现在这个概念本身在某种程度上就是没有明确定义的。如果各个客户端应用彼此隔离,这通常不是大问题;但如果客户端能够通过数据库之外的渠道通信,就可能引起严重的混乱。

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

MVCC之下,全局有效性检查需要额外考虑。例如,一个银行应用可能希望检查一个表中的贷方金额总和等于另一个表中的借方金额总和,而这两个表都在被活跃更新。在读已提交模式下,比较两个连续的SELECT sum(...)命令的结果并不可靠,因为第二个查询很可能会包含第一个查询没有统计到的事务提交结果。在单个可串行化事务中完成这两次求和,只能准确反映在该可串行化事务开始之前已提交事务的效果——但等到结果交付时,人们完全可能合理地怀疑这个答案是否仍然相关。如果可串行化事务本身在尝试进行一致性检查之前已经应用了某些更改,那么这种检查的意义就更加值得商榷,因为此时它包含了事务开始后的一部分而不是全部更改。在这种情况下,谨慎的做法可能是锁定执行检查所需的所有表,以获得当前真实状态的无可争议图景。SHARE模式(或更高)的锁能够保证,在被锁定的表中,除了当前事务自身的更改之外,没有其他未提交更改。

注意,如果依赖显式锁定来防止并发更改,就应当使用读已提交模式,或者在可串行化模式下小心地在执行查询之前先获取锁。可串行化事务获得的锁能够保证没有其他修改该表的事务仍在运行,但如果该事务看到的快照早于获取锁的时刻,那么它看到的快照也可能早于表中某些现在已经提交的更改。可串行化事务的快照实际上是在其第一条查询或数据修改命令(SELECTINSERTUPDATEDELETE)开始时被冻结的,因此可以在快照冻结之前显式获取锁。

提交更正

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