【问题标题】:Rollback in procedure called over dblink通过 dblink 调用的过程中的回滚
【发布时间】:2019-03-21 22:57:44
【问题描述】:

我的情况很奇怪

这有点难以解释,但我会尽力而为

包含 3 个不同的数据库

从 DB1 我调用 DB2 上的函数(通过 dblink)

该过程调用另一个将数据插入 DB3 表中的过程

DB2 上的函数具有 EXCEPTION 句柄,该句柄应该回滚它在异常情况下所做的一切

我运行了示例,一切都很顺利(没有错误),但是从过程 3 中插入​​的内容没有回滚,我必须从 DB1 回滚才能真正回滚

如果我从 db1 提交,则插入行

我是不是做错了什么,有没有办法直接从 db2 上的函数回滚

下面是一些示例代码:

--DB1
PROCEDURE 1
BEGIN
    x := function2@dblink_to_db2();
END;

--DB2
FUNCTION 2
BEGIN
    procedure3();
    RAISE SOME EXCEPTION;
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        do_something_else();
        RETURN 0;
END;

PROCEDURE 3
BEGIN
    INSERT INTO tableA@dblink_to_db3 VALUES ... ;
END;

因此不会引发错误,但不会回滚插入到 db3 上的表中

【问题讨论】:

  • 我没有 3 个数据库来测试它。通过 dblink 调用始终是一个事务。无论您是进行插入还是选择。选择后,您还必须执行提交或回滚。如果在procedure3中引发异常会发生什么?
  • 感谢您的回答。情况是一样的。如果我在程序 3 中引发异常,请在处理程序中回滚,同样的情况,插入的行仍然可以从 db1 中看到。顺便说一句,另一家公司的数据库正在发生这种情况。因此,对于测试,我只使用了 2 个数据库,第一个过程使用 db1,第二个和第三个过程使用 db2,然后通过 dblink 从 db2 插入回 db1。因此,如果您有 2 个数据库,那么您可以通过这种方式重新创建

标签: sql oracle plsql


【解决方案1】:

您必须在引发异常之前或在 Procedure3 中的代码中某处进行提交。我刚刚测试了下面的代码,它在异常之前回滚了所有内容。请忽略命名约定,由于时间限制,不得不去。

数据库 3 创建表温度 (col1 NUMBER);

create or replace procedure testp(i number)
as
BEGIN
    INSERT INTO temp VALUES (i);
END;
/

数据库2

CREATE OR REPLACE FUNCTION DLR_TRANS.testf(i number)
return number
as
e exception;
BEGIN
    testp@TO_DB3(i);
    RAISE e;
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        RETURN 0;
END;
/

数据库1

declare
x number;
BEGIN
    x := testf@TO_DB2(15);
    DBMS_OUTPUT.PUT_LINE ( 'x = ' || x );
    commit;
END;

由于 DB2 的函数异常,x 返回 0。

以下是我在 DB3 上运行以下语句时的数据

select * from temp;

希望对你有帮助

【讨论】:

  • 代码中没有COMMIT。起初我尝试将提交放入其中(由于日志记录),但随后出现错误:ORA-02055:分布式更新操作失败;需要回滚 ORA-02064: 不支持分布式操作 所以该提交被删除。将尝试多玩一点,以弄清楚为什么它对你有用,而不对我有用。谢谢
  • 编辑:复制整个代码(稍作调整)并执行它,在我的情况下插入行。在测试中,我确实只使用了 2 个数据库(因此 testp 在您的示例中位于数据库 1 上),但正如我所说,使用 3 个数据库时也发生了同样的情况。数据库版本是:两个数据库上的 11.2.0.3.0。不知道可能是什么问题
  • 呵呵,我的回复好像没有发表或者可能是我错过了,但是你对代码做了什么小的调整?这应该与 Oracle 版本无关。
【解决方案2】:

问题是您已经“处理”了 [function 2] 中的异常。您根本不应该将异常块放在 [function 2] 中。并让异常传播到 [过程 1]。在这里您将隐式或显式回滚。

如果你必须在 [function 2] 中有一个异常块,那么你应该在最后有一个 [raise]。像这样处理异常是说[我已经处理它,并且出于所有实际目的,调用者不应该认为发生了任何不好的事情]

【讨论】:

  • 是的,这是预期的行为。 DB1 中的过程不希望引发任何错误,DB2 中的函数会做所有需要的事情来检查出错的地方,提醒它需要的人等等(即在 do_something_else(); 调用中)
  • 然后使用其他技术来传达故障。例如。函数可以返回 1 表示成功,您可以使用 x 回滚或提交
猜你喜欢
  • 1970-01-01
  • 2010-11-10
  • 2023-02-17
  • 1970-01-01
  • 1970-01-01
  • 2015-02-18
  • 1970-01-01
  • 2012-03-23
  • 1970-01-01
相关资源
最近更新 更多