Geir Bostad 的回答是正确的;我的回应只是为了提供一个示例和可能的解决方法,因为人们经常难以理解这一点。除了另一个答案中引用的 Wiki 页面之外,还有一个单独的 Wiki 页面仅用于示例,其中包括一个“存款报告”示例,该示例将批次视为已关闭但尚无法查看该批次的最终详细信息。
热备是只读的,所以它只能看到暂时的序列化异常;数据最终会在一些后续事务中稳定到一致的状态。这与主服务器上的可重复读取事务可能发生的情况相同,而主服务器上的可序列化事务则不可能。为防止混淆,在热备份上不允许可序列化事务,因为(还)不能保证在那里看到真正的可序列化事务行为。一直在讨论向 WAL 流添加信息,以识别可以启动可序列化事务的点,而不会有看到异常的风险,DEFERRABLE
类似于START TRANSACTION
; 这个(或类似的东西)可能会在未来的某个版本中添加。
对于使用快照隔离的只读事务(包括在 Oracle 或 9.1 之前的 PostgreSQL 版本中标识为可序列化的事务),最常见的异常类型似乎是 SELECT 列表或汇总在事务中显示为“已关闭”的批处理,没有看到应该包含在批次中的所有工作。要看到这一点,关闭批处理的事务必须“重叠”(同时运行)一些修改批处理详细信息的事务,关闭批处理的事务必须首先提交,然后(在关闭批处理的事务已提交之后和修改批处理详细信息的事务之前提交)只读事务必须启动并获取其快照。
为了防止这种情况,最简单的技术是在主数据库上“提升冲突”,从读写依赖变为写-写冲突。例如,在上面引用的“存款报告”示例中,可以将 deposit_total 列添加到控制表中,当 deposit_no 增加时,AFTER 触发器将其设置为零,并且可以将 AFTER 触发器添加到收据表中以更新金额基于每张收据的金额。这将导致基于控制记录的写入冲突的序列化失败,从而阻止异常传播到副本。