为啥不允许在 PL/SQL 触发器中使用 ROLLBACK 语句,但 RAISE_APPLICATION_ERROR 是?

Posted

技术标签:

【中文标题】为啥不允许在 PL/SQL 触发器中使用 ROLLBACK 语句,但 RAISE_APPLICATION_ERROR 是?【英文标题】:Why is it not allowed to use a ROLLBACK statement in a PL/SQL trigger, but RAISE_APPLICATION_ERROR is?为什么不允许在 PL/SQL 触发器中使用 ROLLBACK 语句,但 RAISE_APPLICATION_ERROR 是? 【发布时间】:2014-06-11 13:01:15 【问题描述】:

如果我错了,请纠正我,但我的印象是调用 RAISE_APPLICATION_ERROR() 会强制回滚。当 ROLLBACK 语句和/或执行 ROLLBACK 语句的方法不允许时,怎么可能在 PL/SQL 触发器中调用 RAISE_APPLICATION_ERROR()?

我觉得我在这里错过了一个关键点:)

提前致谢!

【问题讨论】:

我正在上一门关于 PL/SQL 的课程(这是我的第一年),我们使用的书(荷兰语)指定在调用 RAISE_APPLICATION_ERROR() 后完成 ROLLBACK。我想我将不得不与作者交谈,以澄清声明“回滚”和真正的 ROLLBACK 的区别:) 请允许我补充一点,触发器内的commitrollback 是非常糟糕的做法。如果触发器发现错误,它应该引发一个信息异常并允许围绕 DML 语句的代码确定应该做什么(如果有的话)。根据触发器无法意识到的条件,最佳的操作过程可能是继续、执行部分回滚或中止整个操作。这些不是触发器可以正确做出的决定。 【参考方案1】:

认为自己已得到纠正。有点。引发(或遇到)异常不会导致当前事务的回滚。来自the documentation:

在大多数情况下,如果触发器运行引发异常的语句,并且异常未由异常处理程序处理,则数据库会回滚触发器及其触发语句的影响。

请注意,这是声明,而不是交易;但我想“作用于效果”有点令人困惑......

每个语句周围都有一个隐式保存点,并且触发器异常回滚到该保存点(文档中提到的after 触发器等除外)。来自 Tom Kyte 的专家级 Oracle 数据库架构

Oracle 通过在我们对数据库的每个调用中静默包装一个 SAVEPOINT 来实现这种语句级原子性。

【讨论】:

【参考方案2】:

在触发器内部,RAISE_APPLICATION_ERROR 不会执行 ROLLBACK,它会中止当前操作,即单个 UPDATE/INSERT/DELETE。触发器中的所有内容都属于这样的操作(这也是著名错误“ORA-04091 - 表正在变异,触发器/函数可能看不到它”的原因)。

回滚会还原当前事务中的所有更改(或直到给定的保存点),这是不同的。

【讨论】:

以上是关于为啥不允许在 PL/SQL 触发器中使用 ROLLBACK 语句,但 RAISE_APPLICATION_ERROR 是?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 PL/SQL Oracle 中尝试创建 INSTEAD OF 触发器时出现“错误的绑定变量”错误?

为啥我的 PL/SQL 触发器会引发“错误(2,2):PL/SQL:语句被忽略”和“错误(2,5):PLS-00204:函数或伪列'EXISTS'”错误?

使用 PL/SQL 块创建触发器时出错

PL/SQL 07 触发器 trigger

语句触发器 PL/SQL

使用 PL/SQL 在触发器中中止插入/更新操作