关于pl/sql异常的问题

Jus*_*ner 2 oracle plsql transactions exception

以下文本是oracle文档的摘录Oracle®DatabasePL/SQL语言参考11g第1版(11.1):

未处理的异常也会影响子程序.如果成功退出子程序,PL/SQL会将值分配给OUT参数.但是,如果退出时出现未处理的异常,则PL/SQL不会为OUT参数赋值(除非它们是NOCOPY参数).此外,如果存储的子程序因未处理的异常而失败,则PL/SQL不会回滚子程序完成的数据库工作.

注意粗体文字,这是真的吗?我很好奇,所以我写了下面的例子来测试它.

-- create a test table
CREATE TABLE e AS SELECT * FROM HR.EMPLOYEES;   

-- create p1 which will update a row in table e
CREATE OR REPLACE PROCEDURE p1
IS
    ex EXCEPTION;
    row e%ROWTYPE;
BEGIN
    select * into row from e where employee_id=100;

    row.employee_id := 100;
    row.first_name := 'yang';

    -- update
    UPDATE e set ROW = row where employee_id = 100;
    -- and raise an error
    RAISE ex;
END;


BEGIN
    -- call the upper procedure
    p1;
END;

-- test whether update success
select * from e where employee_id=100;

-- the upper query gives me
Steven
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:我是对的吗?

Vin*_*rat 9

在SO上看到这个问题:Oracle是否因错误而回滚事务?

在您的情况下,过程P1将成功或失败并回滚其更改.为什么它看起来像文档中的声明相反(p1在程序中间失败并且未完成的工作)?

答案在于你引用之前句子:

请记住,如果找不到引发异常的处理程序,PL/SQL会向主机环境返回未处理的异常错误,从而确定结果.例如,在Oracle预编译器环境中,将回滚由失败的SQL语句或PL/SQL块所做的任何数据库更改.

这意味着当程序失败时,如果未处理引发的异常,则将回滚不完整的工作.但是,如果捕获了异常而没有重新引发异常,则不完整的工作将保持不变.

我们可以通过在您的示例中放置一个WHEN OTHERS块(而不是重新引发异常 - 当然这是一个非常糟糕的主意,请参见下面的原因)来显示此行为:

SQL> BEGIN
  2     -- call the upper procedure
  3     p1;
  4  EXCEPTION
  5     WHEN OTHERS THEN
  6        dbms_output.put_line('log error...');
  7  END;
  8  /

log error...

PL/SQL procedure successfully completed

SQL> select employee_id, first_name from e where employee_id = 100;

EMPLOYEE_ID FIRST_NAME
----------- --------------------
        100 yang
Run Code Online (Sandbox Code Playgroud)

你真的不想 这样做:我们离开了未完成的工作,记录了错误,并且没有重新提出它我们有一个潜在的严重错误.此外,默默地忽略异常是灾难的一个方法.