可重复读和可串行化隔离级别都会产生旨在防止序列化异常的错误。如前所述,使用这些级别的应用程序必须准备好重试因序列化错误而失败的事务。此类错误的消息文本会根据具体情况而有所不同,但它总是具有 SQLSTATE 代码 40001
(serialization_failure
)。
重试死锁失败也可能是明智的。这些具有 SQLSTATE 代码 40P01
(deadlock_detected
)。
在某些情况下,重试唯一键失败也是合适的,这些失败具有 SQLSTATE 代码 23505
(unique_violation
),以及具有 SQLSTATE 代码 23P01
(exclusion_violation
) 的排除约束失败。例如,如果应用程序在检查当前存储的键后为主键列选择一个新值,则它可能会得到一个唯一键失败,因为另一个应用程序实例同时选择了相同的新键。这实际上是一个序列化失败,但服务器不会将其检测为序列化失败,因为它无法““看到””插入值与之前读取之间的联系。还有一些特殊情况,即使在原则上服务器有足够的信息来确定序列化问题是根本原因,服务器也会发出唯一键或排除约束错误。虽然建议无条件地重试 serialization_failure
错误,但在重试这些其他错误代码时需要更加小心,因为它们可能表示持久错误条件,而不是瞬态故障。
重要的是重试整个事务,包括决定要发出哪个 SQL 和/或要使用哪个值的全部逻辑。因此,PostgreSQL 不提供自动重试机制,因为它无法以任何保证正确性的方式这样做。
事务重试并不能保证重试的事务将完成;可能需要多次重试。在争用非常高的案例中,完成事务可能需要多次尝试。涉及冲突的已准备事务的情况,在已准备事务提交或回滚之前,可能无法取得进展。