我有一个主过程(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>;
现在的问题是:
- 如果使用嵌套的BEGIN,嵌套代码中的COMMIT Inside可以COMMIT所有内容,而外部块中的ROLLBACK将不执行任何操作(不回滚内部的COMMIT之前发生的任何内容
- 如果您使用SAVEPOINT,它只用于回滚部分代码,即使您进行了COMMIT,外部块中的ROLLBACK也会回滚SAVEPOINT