关于pl/sql异常的问题
以下文本摘录自 Oracle 文档Oracle® Database PL/SQL 语言参考 11g 第 1 版 (11.1):
未处理的异常也会影响 子程序。如果退出子程序 成功后,PL/SQL 将值分配给 输出参数。但是,如果您退出 带有未处理的异常,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
所以我的问题是:我说得对吗?
the following text is an excerpt of oracle documentation Oracle® Database PL/SQL Language Reference 11g Release 1 (11.1) :
Unhandled exceptions can also affect
subprograms. If you exit a subprogram
successfully, PL/SQL assigns values to
OUT parameters. However, if you exit
with an unhandled exception, PL/SQL
does not assign values to OUT
parameters (unless they are NOCOPY
parameters). Also, if a stored
subprogram fails with an unhandled
exception, PL/SQL does not roll back
database work done by the subprogram.
note the bold text, does that true? i'm curious about that, so i wrote the following example to test it.
-- 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
so my question is: am i right?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
请参阅以下问题: Oracle 回滚吗事务发生错误?
在您的情况下,过程 P1 将成功或失败并回滚其更改。为什么文档中的语句看起来相反(p1 在过程中间失败并留下未完成的工作)?
答案就在 报价前的句子:
这意味着当过程失败时,如果引发的异常未得到处理,未完成的工作将被回滚。但是,如果异常被捕获并且没有重新引发,则未完成的工作将保持原样。
我们可以通过在您的示例中放置 WHEN OTHERS 块(而不是重新引发异常 - 当然这是一个非常非常糟糕的主意,请参阅下面的原因)来展示此行为:
您真的< a href="http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:4018285967344#671326800346790791" rel="nofollow noreferrer">永远不要 执行此操作 :我们留下了未完成的工作,错误被记录下来,如果不重新引发它,我们就有一个潜在的严重错误。此外,默默地忽视例外情况会导致灾难。
See this question on SO: Does Oracle roll back the transaction on an error?
In your case the procedure P1 will either succeed or fail and roll back its changes. Why does it look like the statement from the documentation states the opposite (p1 fails in the middle of the procedure and leaves unfinished work)?
The answer lies in the sentence just before your quote:
What this means it that when a procedure fails, if the raised exception is unhandled, the incomplete work will be rolled back. However, if the exception is catched and not re-raised the incomplete work will be left as is.
We can show this behaviour by putting a WHEN OTHERS block (and not re-raising an exception -- of course it's a really really bad idea see below why) in your example:
You really never want to do this: we left unfinished work, the error is logged and by not re-raising it we have a potentially serious bug. Furthermore, silently ignoring exceptions is a recipe for disasters.
“此外,如果存储子程序因未处理的异常而失败,PL/SQL 不会回滚该子程序完成的数据库工作。”
上面的引用特指存储子程序,但以下代码块是一个匿名块,而不是存储的子程序
因此,引用不适用。顶级匿名块的失败是执行回滚的原因(就像任何其他 SQL 语句一样)
使用以下代码进行测试表明,当 SERVERERROR 触发器被触发时(即返回主机之前),值 1 和 10 的 INSERT 已经回滚(因为重新插入 1 不会失败)重复键或死锁)。
支持这一假设的另一种情况。在这种情况下,匿名 PL/SQL 块在嵌套在另一个 PL/SQL 块内的 EXECUTE IMMEDIATE 中调用。尽管异常被外部块捕获,但当 EXECUTE IMMEDIATE 运行原子语句时,插入已经回滚。
"Also, if a stored subprogram fails with an unhandled exception, PL/SQL does not roll back database work done by the subprogram."
The above quote specifically refers to stored subprograms, but the following chunk of code is an anonymous block, not a stored subprogram
As such, the quote does not apply. The failure of the top level anonymous block is the one that does the rollback (just as any other SQL statement)
Testing with the following code indicates that, by the time the SERVERERROR trigger is fired (ie BEFORE returning to the host), the INSERTs of values 1 and 10 have already been rolled back (because a re-insert of the 1 doesn't fail on duplicate key or deadlock).
Another scenario supporting this hypothesis. In this case the anonymous PL/SQL block is called within an EXECUTE IMMEDIATE nested inside another PL/SQL block. Although the exception is captured by the outer block, the insert has already been rolled back as EXECUTE IMMEDIATE runs an atomic statement.