在postgresql / PL / pgSQL中创建函数时,元组会同时更新

时间:2016-11-10 10:47:34

标签: postgresql

初始化我的进程时,它运行下面的PL / pgSQL语句,创建两个函数。但是,每当我作为端到端测试的一部分同时创建多个进程时,此语句的并行执行会导致tuple concurrently updated错误,我似乎无法解决这个问题。任何帮助将不胜感激。

CREATE OR REPLACE FUNCTION
  count_rows(schema text, tablename text) returns integer
  AS
  $body$
  DECLARE
    result integer;
    query varchar;
  BEGIN
    query := 'SELECT count(1) FROM "' || schema || '"."' || tablename || '"';
    execute query into result;
    return result;
  END;
  $body$
  LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION
  delete_if_empty(schema text, tablename text) RETURNS INTEGER
  AS
  $$
  DECLARE
    result integer;
    query varchar;
  BEGIN
    query := 'SELECT COUNT(*) FROM "' || schema || '"."' || tablename || '"';
    execute query into result;
    IF result = 0 THEN
      EXECUTE 'DROP TABLE "' || schema || '"."' || tablename || '" CASCADE;';
      EXECUTE 'NOTIFY "' || schema || '", ''DESTROY_TABLE:' || tablename || ''';';
      RETURN 1;
    END IF;
    RETURN 0;
  END;
  $$
  LANGUAGE plpgsql;

  SELECT version()

1 个答案:

答案 0 :(得分:2)

正如here所述,postgres目前不允许同时使用CREATE FUNCTION

  

有必要添加   如果你想同时避免"元组,那么某种锁定方案   更新"错误。这与情况没有任何不同   其中两个事务都想要更新用户表中的同一行:   除非应用程序采取额外步骤来序列化更新,否则您就是其中之一   得到"元组同时更新"错误。

     

我们对表/索引上的DDL有这样的锁定,但是理论在   过去一直认为它不值得为它所代表的对象带来麻烦   单个目录行,例如函数或角色。

解决方案是确保没有两个交易同时尝试CREATE FUNCTION

您可以使用posgres 顾问锁

可在此处找到有关咨询锁的详细介绍:https://vladmihalcea.com/how-do-postgresql-advisory-locks-work/

例如,您可以使用:

BEGIN; -- start of transaction

SELECT pg_advisory_xact_lock(2142616474639426746); -- random 64-bit signed ('bigint') lock number

CREATE OR REPLACE FUNCTION myfunction ...

COMMIT;

这需要一个事务级别的独占顾问锁,这样就不能同时运行两个并发事务来创建该函数。在交易结束时,锁定会自动释放。