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开发吗?