我很难理解 Postgres 中的事务。我有一个可能会遇到异常的过程。到目前为止,我可能希望在程序的某些部分提交我的工作,以便在出现异常时不会回滚。
我希望在捕获异常并将异常信息插入日志记录表的过程结束时有一个异常处理块。
我将问题归结为一个简单的过程,如下所示,该过程在 PostgreSQL 11.2 上失败了
2D000 cannot commit while a subtransaction is active
PL/pgSQL function x_transaction_try() line 6 at COMMIT
drop procedure if exists x_transaction_try;
create or replace procedure x_transaction_try()
language plpgsql
as $$
declare
begin
raise notice 'A';
-- TODO A: do some insert or update that I want to commit no matter what
commit;
raise notice 'B';
-- TODO B: do something else that might raise an exception, without rolling
-- back the work that we did in "TODO A".
exception when others then
declare
my_ex_state text;
my_ex_message text;
my_ex_detail text;
my_ex_hint text;
my_ex_ctx text;
begin
raise notice 'C';
GET STACKED DIAGNOSTICS
my_ex_state = RETURNED_SQLSTATE,
my_ex_message = MESSAGE_TEXT,
my_ex_detail = PG_EXCEPTION_DETAIL,
my_ex_hint = PG_EXCEPTION_HINT,
my_ex_ctx = PG_EXCEPTION_CONTEXT
;
raise notice '% % % % %', my_ex_state, my_ex_message, my_ex_detail, my_ex_hint, my_ex_ctx;
-- TODO C: insert this exception information in a logging table and commit
end;
end;
$$;
call x_transaction_try();
为什么这个存储过程不起作用?为什么我们从来没有看到它的输出,raise notice 'B'
而是进入了异常块?是否可以使用 Postgres 11 存储过程执行我上面描述的操作?
编辑:这是一个完整的代码示例。将上述完整代码示例(包括create procedure
andcall
语句)粘贴到 sql 文件中,并在 Postgres 11.2 数据库中运行以进行重现。所需的输出将是函数打印A
then B
,但它会打印A
thenC
以及异常信息。
另请注意,如果您注释掉所有异常处理块,使得该函数根本不捕获异常,则该函数将输出“A”然后“B”而不会发生异常。这就是为什么我将这个问题命名为“在具有异常块的过程中是否存在 Postgres 提交?”