Postgres:在回滚之前保存临时表中的行



我有一个主过程(p_proc_a(,在其中我创建了一个用于日志记录的临时表(tmp.log(。在主过程中,我调用了一些其他过程(p_proc_b,p_proc_c(。在每一个过程中,我都会将数据插入表tmp.log中。

在回滚之前发生异常时,如何将tmp.log中的行保存到物理表(日志(中?

create procedure p_proc_a
language plpgsql
as $body$
begin
create temp table tmp_log (log_message text) on commit drop;
call p_proc_b();
call p_proc_c();
insert into log (log_message) 
select log_message from tmp_log;
exception
when others then
begin
get stacked diagnostics
v_message_text = message_text;
insert into log (log_message)
values(v_message_text);
end;
end;
$body$

将日志保存到表中并回滚p_proc_b和p_proc_c的更改的工作循环是什么?

这在PostgreSQL中是不可能的。

典型的解决方法是使用dblink连接到数据库本身,并通过dblink写入日志。

我找到了三种在事务中存储数据的解决方案(在我的情况下,用于调试建议(,并且在rollback处理事务后仍然能够看到这些数据

我有一个场景,在里面,我使用下面的块,所以它可能不适用于您的场景

DO $$
BEGIN
...
ROLLBACK;
END;
$$;

在Postgres slack中向我建议了两种第一种解决方案,另一种是我在与他们交谈后尝试并找到的,这种方法在其他数据库中也适用。

解决方案

1-使用DBLink

我不记得它是如何完成的,但你导入了一些库,然后连接到另一个数据库,并使用另一个db-,它可能支持成为这个数据库-它似乎不受事务的影响

2-使用COPY命令

使用

COPY (SELECT ...) TO PROGRAM 'psql -c "COPY xyz FROM stdin"'

顺便说一句,我从未使用过它,而且它似乎需要Unix中的Super User(SU(权限。天知道它是如何使用的,或者它是如何输出数据的

3-使用子交易

通过这种方式,您使用一个子事务(我不确定它是否正确,但它必须被称为自治事务(来提交您想要保留的结果。在我的情况下,命令如下所示:我使用了一个Temp表,但它似乎(我不确定(也能使用实际的表

CREATE TEMP TABLE
IF NOT EXISTS myZone AS
SELECT * from public."Zone"
LIMIT 0;
DO $$
BEGIN
INSERT INTO public."Zone" (...)VALUES(...);
BEGIN
INSERT INTO myZone
SELECT * from public."Zone";
commit;
END;
Rollback;
END; $$;
SELECT * FROM myZone;
DROP TABLE myZone;

不要问这样做的目的是什么,我正在创建一个测试场景,我希望跟踪到现在为止我做了什么。由于这个块不支持DQL的SELECT,我不得不做其他事情,并且我想要一组干净的报告,而不会引发错误

根据www.techtarget.com:

*自治事务允许将单个事务细分为多个提交/回滚事务,每个事务将出于审计目的进行跟踪。当自主交易被调用,原始事务(调用事务(为暂时中止

(此文本由谷歌索引,存在于2022-10-11,由于电子邮件验证问题,网站未打开(

此外,这个名字似乎来自Oracle,本文可以将其与联系起来

EIDTED:

删除解决方案3,因为它不起作用

POSTGRES 11声称支持Autonomous Transactions,但这不是我们所期望的。。。

为此,Postgres引入了SAVEPOINT:

SAVEPOINT <name of savepoint>;
<... CODE ...>

<RELEASE|ROLLBACK> SAVEPOINT <name of savepoint>;

现在的问题是:

  1. 如果使用嵌套的BEGIN,嵌套代码中的COMMIT Inside可以COMMIT所有内容,而外部块中的ROLLBACK将不执行任何操作(不回滚内部的COMMIT之前发生的任何内容
  2. 如果您使用SAVEPOINT,它只用于回滚部分代码,即使您进行了COMMIT,外部块中的ROLLBACK也会回滚SAVEPOINT

最新更新