PL/pgSQL 函数会自行自动提交吗?

Posted

技术标签:

【中文标题】PL/pgSQL 函数会自行自动提交吗?【英文标题】:Do PL/pgSQL functions autocommit on their own? 【发布时间】:2021-07-17 00:36:05 【问题描述】:

我在 PostgreSQL 11 上有一个 PL/pgSQL 函数如下:

create or replace function public.process_single_usage(usage_p "UsagePs")
  returns text
  language plpgsql
as $function$
declare
return_msg text;
   -- Variables used for business logic
begin
   -- Business logic and error handling, return_msg variable is assigned to an error message on failure 
   -- or to an empty string on success.

   -- A bunch of insert statements if no error arises.
   return return_msg;
end
$function$;

我是否可以使用第二个函数在表的每一行上运行第一个函数,并在任何一行出现错误消息时回滚每个插入,或者我是否需要使用单个函数来控制事务?

【问题讨论】:

该函数始终是调用者事务的一部分。而且你不能在函数中使用提交或回滚 那么,既然一个函数正在调用,那是否意味着在给定时间有两个事务,一个嵌套另一个? 不,一切都在由第一个函数的调用者定义的单个事务中运行 @a_horse_with_no_name:虽然这是真的,但我认为这不会妨碍 OP 试图实现的目标。我添加了一个答案。 那么你有答案了吗? 【参考方案1】:

我是否可以使用第二个函数在表的每一行上运行第一个函数,并在任何一行结果出现错误消息时回滚每个插入

FUNCTION 始终在单个事务中运行。但我不认为这会妨碍您尝试做的事情。带有EXCEPTION 子句的block 可以捕获异常并回滚子事务。根据“每个插入”的确切含义,这可能对您有用。

如果“每一行”是指整个操作中的每一行(子函数的多次调用),那么你不需要做任何额外的事情。如果发生异常,回滚一切是默认行为。

如果“每一行”是指受子函数的单个调用影响的每一行,那么考虑the manual on Trapping Errors:

EXCEPTION 子句捕获到错误时,局部变量 PL/pgSQL 函数的 PL/pgSQL 函数保持错误发生时的状态, 但是块内对持久数据库状态的所有更改都是 回滚

我的大胆强调。相关:

PostgreSQL cannot begin/end transactions in PL/pgSQL

要真正 COMMIT 在过程中的任何点工作,您需要一个 PROCEDURE,它在 Postgres 11 中引入。从相同版本开始,事务控制语句也允许在使用 DO command 执行的匿名代码块中.

基本上:

DO
$do$
DECLARE
  _rec "UsagePs";
BEGIN
   FOR _rec IN
      SELECT * FROM "UsagePs" u WHERE u.foo = 'bar' ORDER BY u.id
   LOOP
      BEGIN 
         PERFORM public.process_single_usage(_rec);
         -- COMMIT; -- ? -- requires Postgres 11
      EXCEPTION
         WHEN OTHERS THEN
            RAISE WARNING 'This error happened: %!', SQLERRM;
      END;
   END LOOP;
END
$do$;

我认为您甚至不需要或不想在循环中使用COMMIT。您只想回滚子事务 - 或所有内容。

注意使用SQLERRM 将任何错误消息从子函数传播出去,降级为WARNING。 The manual:

特殊变量SQLERRM 包含与异常相关的错误消息。

相关:

Can I use EXCEPTIONs in a FOR LOOP to force continuation on error? PostgreSQL INSERT or UPDATE values given a SELECT result after a trigger has been hit

【讨论】:

以上是关于PL/pgSQL 函数会自行自动提交吗?的主要内容,如果未能解决你的问题,请参考以下文章

有一个PL / pgSQL免费环境可以为PostgreSQL开发吗?

Postgres PL/pgSQL,可以声明匿名自定义类型吗?

PL/pgSQL 函数在 pgAdmin 之外无法正确运行

从自动完成列表提交查询,而无需点击提交按钮

审核通过后,应用会自动发布到商店吗?

spring boot mysql 事务