PostgreSQL异常:DB_Cursor:执行中的异常:tuple并发更新

时间:2014-05-05 17:18:21

标签: python postgresql

作为升级过程的一部分,我们的产品脚本会更新触发器的存储过程。有两个守护进程正在运行,其中任何一个都可以更新存储过程。似乎PostgrSQL没有序列化DDL来升级程序。确切的错误是" DB_Cursor:执行中的异常:元组并发更新"。 Google搜索在搜索结果中不会与此错误产生完全匹配。看来我们有竞争条件。避免或阻止此类异常的最佳方法是什么?它会阻止升级过程成功,并且必须重新启动一个或两个进程(守护程序)才能重试升级和恢复。 PostgreSQL存在已知问题吗?我们正在运行PostgreSQL 9.2.5。

2 个答案:

答案 0 :(得分:1)

  

似乎PostgreSQL没有序列化DDL来升级   程序

是。这在pgsql邮件列表中不时被提及,例如最近在这里:

'tuple concurrently updated' error when granting permissions

摘录:

  

我们对表/索引上的DDL有这样的锁定,但是理论在   过去一直是对物体不值得的麻烦   由单个目录行表示,例如函数或角色。您   不能在这样的行上同时更新来破坏数据库,   你只会得到一个“元组并发更新”错误   首次到达的更新。

如果您同时更换功能体,这显然是您的问题。

建议的解决方案是:

  

与此同时,您可以考虑使用应用程序管理   如果你真的需要这样的补助来透明地工作,那就提供咨询锁。

答案 1 :(得分:1)

如果设计多个并发客户端可以决定执行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;
}