在执行 postgreql 函数时提交事务

Posted

技术标签:

【中文标题】在执行 postgreql 函数时提交事务【英文标题】:Committing transactions while executing a postgreql Function 【发布时间】:2014-04-16 13:25:07 【问题描述】:

我有 Postgresql 函数,它必须向表中插入大约 150 万条数据。我想要的是我希望看到每个记录插入都会填充表格。目前,当我尝试说大约 1000 条记录时会发生什么,只有在完整的函数执行后才会填充 get 。如果我在中途停止该功能,则不会填充任何数据。即使在插入一定数量的记录后停止,如何提交记录?

【问题讨论】:

Are PostgreSQL functions transactional?的可能重复 【参考方案1】:

这可以使用 dblink 来完成。我展示了一个示例,其中提交了一个插入,您将需要添加您的 while 循环逻辑并提交每个循环。你可以http://www.postgresql.org/docs/9.3/static/contrib-dblink-connect.html

CREATE OR REPLACE FUNCTION log_the_dancing(ip_dance_entry text)
RETURNS INT AS
$BODY$
    DECLARE
    BEGIN
        PERFORM dblink_connect('dblink_trans','dbname=sandbox port=5433 user=postgres');
        PERFORM dblink('dblink_trans','INSERT INTO dance_log(dance_entry) SELECT ' || '''' || ip_dance_entry || '''');
        PERFORM dblink('dblink_trans','COMMIT;');
        PERFORM dblink_disconnect('dblink_trans'); 

        RETURN 0;
    END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

ALTER FUNCTION log_the_dancing(ip_dance_entry text)
  OWNER TO postgres;

BEGIN TRANSACTION;
  select log_the_dancing('The Flamingo');
  select log_the_dancing('Break Dance');
  select log_the_dancing('Cha Cha');
ROLLBACK TRANSACTION;

--Show records committed even though we rolled back outer transaction
select *
from dance_log;

【讨论】:

我通常只在记录时使用这种方法。除了记录之外,它通常不是进行批量提交的正确方法,但我会留给你为你的用例决定。 dblink 是否可用于 postgresql 9.2? 是的,你应该可以执行 CREATE EXTENSION dblink;从作为 postgres 用户连接的 SQL 会话中进行测试。 感谢您的帮助。我会试试这个。 @Bob 当您想在某个时间间隔提交以避免丢失工作(以及因此时间)时,它对于长时间运行的加载/转换/生成过程也很有用。可以说这属于应用程序层(或在 shell 脚本或其他东西中),但有时我必须手动完成此类工作,并且非常感谢在 DB 中使用更轻量级的方式。【参考方案2】:

您所要求的通常称为自治事务

PostgreSQL 目前不支持自治事务 (9.4)。

要正确支持它们,它确实需要存储过程,而不仅仅是它当前支持的用户定义函数。由于与会话和进程模型相关的各种内部原因,在 PostgreSQL 中实现自治 tx 也非常复杂。

现在,按照 Bob 的建议使用 dblink。

【讨论】:

【参考方案3】:

对于 Postgresql 9.5 或更高版本,您可以使用 pg_background 扩展提供的动态后台工作程序。它创建了自治事务。请参考扩展的github page。解决方案比 db_link 更好。在Autonomous transaction support in PostgreSQL 上有完整的指南。在 Postgres 中还有第三种启动自治事务的方法,但需要一些补丁。有关 OracleDB 样式的事务,请参阅 Peter 的 Eisentraut patch proposal。

【讨论】:

【参考方案4】:

如果您可以灵活地从函数更改为过程,从 Postgresql 12 开始,如果您使用过程而不是函数,则可以执行内部提交,由 CALL 命令调用。因此,您的函数将更改为过程并使用 CALL 命令调用:例如:

    CREATE PROCEDURE transaction_test2()
    LANGUAGE plpgsql
    AS $$
    DECLARE
     r RECORD;
    BEGIN
      FOR r IN SELECT * FROM test2 ORDER BY x LOOP
        INSERT INTO test1 (a) VALUES (r.x);
        COMMIT;
      END LOOP;
    END;
    $$;

    CALL transaction_test2();

有关 Postgres 事务管理的更多详细信息,请访问:https://www.postgresql.org/docs/12/plpgsql-transactions.html

【讨论】:

以上是关于在执行 postgreql 函数时提交事务的主要内容,如果未能解决你的问题,请参考以下文章

js:nodejs通过async异步提交事务数据

当页面提交时,执行相关JS函数检查输入是否合法

spring执行事务提交后进行一些逻辑操作

Hibernate核心类用法-使用Transaction管理事务

事务与自动提交

redis避免大事务提交失败