初始化我的进程时,它运行下面的 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()
Run Code Online (Sandbox Code Playgroud)
如此处所述,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;
Run Code Online (Sandbox Code Playgroud)
这需要事务级独占咨询锁,因此没有两个并发事务可以同时运行创建函数。事务结束时,锁会自动释放。