[英]PostgreSQL Exception: DB_Cursor: exception in execute: tuple concurrently updated
作为升级过程的一部分,我们的产品脚本会更新触发器的存储过程。 有两个运行中的守护程序,其中两个都可以更新存储过程。 似乎PostgrSQL并未序列化DDL以升级该过程。 确切的错误是“ DB_Cursor:执行中的异常:元组同时更新”。 Google搜索不会在搜索结果中找到与此错误完全匹配的结果。 看来我们有比赛条件。 避免或防止此类异常的最佳方法是什么? 这会阻止升级过程成功进行,并且必须重新启动一个或两个过程(守护程序)以重试升级并恢复。 PostgreSQL是否存在已知问题? 我们正在运行PostgreSQL 9.2.5。
似乎PostgreSQL没有序列化DDL来升级程序
是。 有时在pgsql邮件列表中提到这一点,例如最近在这里:
摘抄:
我们确实对表/索引上的DDL进行了这种锁定,但是过去的理论一直认为,对于由单个目录行表示的对象(例如函数或角色),这是不值得的。 您不能在这样的行上通过并发更新来破坏数据库,除了从先到先得的更新之外,您只会收到“ tuple同时更新 ”错误。
如果要同时替换函数主体,那么显然这是您的问题。
提出的解决方案是:
同时,如果您确实需要这种授予以透明地工作,则可以考虑使用应用程序管理的咨询锁。
如果根据设计,多个并发客户端可以决定执行DDL,那么您确实应该确保只有其中一个正在执行DDL。 您可以使用咨询锁来做到这一点。
伪代码示例:
function try_upgrade(db) {
if ( ! is_upgrade_needed(db) ) {
// we check it before acquiring a lock to speed up a common case of
// no upgrade available
return UPGRADE_NOT_NEEDED;
}
query_result = db->begin_transaction();
if ( query_result < 0 ) throw Error("begin failed");
query_result = db->query(
"select pg_advisory_xact_lock(?)", MAGIC_NUMBER_UPGRADE_LOCK
);
if ( query_result < 0 ) throw Error("pg_advisory_xact_lock failed");
// another client might have performed upgrade between the previous check
// and acquiring advisory lock
if ( ! is_upgrade_needed(db) ) {
query_result = db->rollback_transaction();
return UPGRADE_NOT_NEEDED;
}
perform_upgrade();
query_result = db->commit_transaction();
if ( query_result < 0 ) throw Error("commit failed");
return UPGRADE_PERFORMED;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.