繁体   English   中英

PostgreSQL异常:DB_Cursor:执行异常:元组同时更新

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM