是否可以使 oracle 数据库过程忽略提交语句?

Posted

技术标签:

【中文标题】是否可以使 oracle 数据库过程忽略提交语句?【英文标题】:Is it possible to make oracle database procedures to ignore commit statements? 【发布时间】:2013-06-20 05:53:38 【问题描述】:

我正在开发与编写的 Oracle PL/SQL 遗留系统集成的 Java 应用程序。不幸的是,我无法更改这个遗留系统。这个系统的问题是它有时将 COMMIT 语句写入过程。但这导致我无法在我的应用程序级别正确处理事务。

那么是否可以让 oracle 数据库过程忽略提交语句?

我发现在连接开始时执行ALTER SESSION DISABLE COMMIT IN PROCEDURE 会在PL/SQL 过程尝试提交时导致异常。但是是否可以让 Oracle 在不更改 PL/SQL 代码的情况下忽略提交?

【问题讨论】:

呃,你为什么要这么做? @fge,如果过程提交,如果后续操作导致错误,调用事务将无法回滚。 “我无法更改此旧系统” 但禁用应用程序中的 COMMIT 语句不是更改? 【参考方案1】:

我认为你做不到。您必须向这些过程添加一个参数,例如“do commit”,默认值为 true。并且您将参数设置为 false 来调用它们。如果它们是嵌套的,则传递参数值。这样,遗留代码的行为仍然相同,但您可以获得事务控制。

【讨论】:

【参考方案2】:

我在 Oracle 工作了 9 年。我还检查了有关您的问题的未记录参数,并且我很确定,没有办法让 Oracle 忽略存储过程的提交。

但是,理论上,您可以使用 Oracle 的闪回功能(例如闪回数据库或闪回表)将整个数据库或单个表重置为事务开始之前的状态。但是请注意,如果您是唯一一个在您闪回的对象上更改任何内容的人,那么这只会根据需要起作用。这通常是不现实的。顺便说一句,您还需要考虑闪回功能并非旨在支持这种情况,因此如果您需要闪回任何内容,您的应用程序的性能将不是最佳的。 但是,如果您别无选择,这可能是解决您问题的一种方法。

【讨论】:

【参考方案3】:

也许最好的办法是在不影响当前功能的情况下更改 pl/sql 过程。换句话说,添加一个新参数以允许用户忽略提交,但默认为现有功能(提交)。我在类似的情况下做过这个,效果很好。

所以,你会有类似的东西:

create or replace procedure some_proc(
    i_num in number, -- existing parameter
    i_commit in number default 1) -- perform commit? 0=false, else true
as

begin
  -- some DML here

  if (i_commit <> 0) then
    commit;
  end if;

end;

确保将此新参数添加到参数列表的末尾。因此,您的应用将为 i_commit 传递 0(假)。

希望对您有所帮助。

【讨论】:

【参考方案4】:

我在做ALTER SESSION DISABLE COMMIT IN PROCEDURE的时候发现 PL/SQL 程序在连接开始时会导致异常 正在尝试提交。

是的,该语句的记录行为是在程序尝试发出提交时强制 ORA-00034 异常。我认为它的真正目的是作为一种测试,以识别具有嵌入式提交的过程。

我认为存储过程发出提交被广泛认为是不好的做法。事务的控制权必须属于调用栈的顶部。

不幸的是,没有办法忽略那些嵌入的提交。您要么必须重新编写 PL/SQL 例程,要么在调用代码中编写一些变通方法(例如,发出额外 DML 以反转已提交更改的异常处理程序)。

【讨论】:

【参考方案5】:

了解程序的作用会有所帮助。 但是,假设该过程修改了有限数量的表中的数据(这就是我们在 PLSQL 中最常做的事情),您可以尝试在该模式上运行闪回查询:

闪回表 TABLE_NAME 到 TIMESTAMP(TO_DATE('06-SEP-2012 23:59:59','DD-MON-YYYY HH24: MI: SS'));

您可以将时间字符串“06-SEP-2012 23:59:59”设置为在您的 JAVA 代码中调用该过程之前的时间。

这是一个糟糕的解决方法,但我想值得一试

【讨论】:

这并没有比现有答案更多的信息。您可以通过构建仅回滚特定事务的解决方案来扩展它们。也许通过使用VERSIONS_XID,或者使用dbms_application_info.set_client_info 和审计触发器来手动撤消一组更改,或者使用logminer。这可能不能直接解决如何忽略提交的问题,但它会是一个很好的解决方法并且值得赏金。【参考方案6】:

我正在开发与遗留系统集成的 Java 应用程序 编写 Oracle PL/SQL。不幸的是我无法改变这个 旧系统。

嗯,这闻起来像政治......“不要碰这个,它有效!”我猜。 :(

事实上,正如@Tilman Fliegel(和其他人)已经说过的那样,忽略COMMIT 声明很可能是不可能的。如果是这样,那将是您代码库中的一个非常丑陋的疣。

我不太擅长政治,但我想说如果你不能使用也不能改变它,那么就不要使用它。我的意思是:

如果您无法更改您的过程,因为它们被其他(旧的、不可变的)系统使用,则复制它们,然后修改/重构您的副本,直到您满意为止。如果您能够使您的版本兼容,您甚至可以为其他(旧)系统提供一种方式,以便在/如果它们被重构时使用您的系统:只需引入“传统模式”输入参数或其他任何东西,cf .其他答案。 如果您因为无法理解/测试代码而无法更改代码,那么这是一个主要问题。将其丢弃并从头开始(只要您能够这样做)甚至可能更安全。

但也许尝试忽略COMMITs 毕竟更容易。人类很难重构... ;)

【讨论】:

以上是关于是否可以使 oracle 数据库过程忽略提交语句?的主要内容,如果未能解决你的问题,请参考以下文章

oracle存储过程中循环调用存储过程

Oracle 函数不是过程或未定义。语句被忽略

Oracle 中的事务

在 oracle 中执行存储过程后是不是发生任何自动提交?

关于oracle的事务中,如何判断一条语句是不是成功执行

ORACLE:错误错误(6,3):PL/SQL:SQL 语句被忽略和错误(8,3):PL/SQL:ORA-00933:SQL 命令未在过程中正确结束