【问题标题】:DML and Exception Handling - OracleDML 和异常处理 - Oracle
【发布时间】:2015-11-05 09:25:08
【问题描述】:

根据 Steven Feuerstein 的书

PL/SQL 块发生异常时,Oracle 数据库不回滚 该块中 DML 语句所做的任何更改。您是应用程序逻辑事务的管理者,因此您决定应该发生什么样的行为。
我试试看:

CREATE TABLE DML_Exception (exception_name VARCHAR2(20));
INSERT INTO DML_exception  VALUES('CASE_NOT_FOUND');
INSERT INTO DML_exception  VALUES('TOO_MANY_ROWS');

我的表中有两行

Select * from DML_Exception

现在我从表中删除了两行并在 PL/SQL 块中引发了异常。

BEGIN
  DELETE FROM dml_exception;
  raise value_error;
END;

但我的表格仍然包含这两行。我错过了什么?

【问题讨论】:

  • 未提交的事务?
  • 你用的是什么客户端?也许它会在异常后回滚?
  • 作为@Stawros sadid,你忘记了提交
  • 关于事务和游标行为的一些基本原则的一个很好的问题。

标签: oracle


【解决方案1】:

您错过了本书的其他部分。是的,Steven 是对的——如果一个异常发生在一个块中,所有之前的 DML 效果都会保持原样。然而,书中还应该提到任何顶级 SQL 或 PL/SQL 语句(即匿名块)执行都会为该语句打开一个游标,如果游标执行期间出现异常,所有 DML 效果都会完成在游标执行期间回滚。也许一个简单的例子会给你线索......

在您的原始示例中,您执行了 ...

BEGIN
    DELETE FROM dml_exception;
    raise value_error;
END;

... 作为顶级语句。是的,在区块的末尾,尽管仍在其中,但您的 delete 效果仍然存在。然而,您的块引发了一个异常,该异常一直传播到顶级光标。因此,为了遵守atomicity 的原则,Oracle 回滚了已打开游标的所有待处理效果。

如果您从另一个顶级 PL/SQL 块中调用您的 PL/SQL 块,该块处理并且不会重新引发在较低级别 PL/SQL 块中引发的异常,...

BEGIN
    BEGIN
        DELETE FROM dml_exception;
        raise value_error;
    END;
EXCEPTION
    WHEN others THEN NULL;
END;

...,那么您的delete 效果将保持不变。 (并且由于该块中没有提交,因此您最终会有一个正在进行的事务。)

【讨论】:

  • 谢谢你的帮助,我的概念现在很清楚了:)
猜你喜欢
  • 2010-12-30
  • 1970-01-01
  • 2018-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多