ORA-4088、ORA-6512 使用触发器和 RAISE_APPLICATION_ERROR

Posted

技术标签:

【中文标题】ORA-4088、ORA-6512 使用触发器和 RAISE_APPLICATION_ERROR【英文标题】:ORA-4088, ORA-6512 Using Triggers and RAISE_APPLICATION_ERROR 【发布时间】:2020-06-06 14:36:08 【问题描述】:

在尝试使用触发器在 Oracle 中强制执行外键完整性时

CREATE OR REPLACE TRIGGER TRG_IU_SPONSORID_user_registration
BEFORE INSERT OR UPDATE OF U_SPONSORID ON user_registration
FOR EACH ROW
DECLARE l_SPONSORID VARCHAR2 (2000);
BEGIN 
 SELECT U_SPONSORID 
 Into l_SPONSORID
 FROM U_SPONSOR WHERE U_SPONSORID = :NEW.U_SPONSORID;
 If l_SPONSORID is null
        THEN raise_application_error(-20010, 'Not a valid SPONSORID: '|| ':NEW.U_SPONSORID');
  End if;
 END;

我收到以下错误,但未打印引发错误消息

ORA-6512: at "BPORTD1.TRG_IU_SPONSOR_USER_REGISTRATION", line 3
ORA-4088: error during execution of trigger 'BPORTD1.TRG_IU_SPONSOR_USER_REGISTRATION'

​知道为什么会这样吗?

【问题讨论】:

【参考方案1】:

你写的代码有 1.5 个错误:

1st:如果U_SPONSOR 表中没有这样的行,select 不会像你想的那样返回NULL,但是no_data_found 你应该处理;我想这就是发生在你身上的事 0.5th:从dbms_output.put_line 中的':new.u_sponsorid' 中删除单引号,因为您将按字面意思显示,而不是ID 值。

示例表和触发器:

SQL> create table u_sponsor (u_sponsorid number);

Table created.

SQL> create table user_registration(u_sponsorid number);

Table created.

SQL> create or replace trigger trg_iu_sponsor
  2    before insert or update of u_sponsorid on user_registration
  3    for each row
  4  declare
  5    l_sponsorid varchar2 (2000);
  6  begin
  7   select u_sponsorid
  8     into l_sponsorid
  9     from u_sponsor
 10     where u_sponsorid = :new.u_sponsorid;
 11  exception
 12    when no_data_found then
 13      raise_application_error(-20010,
 14        'Not a valid SPONSORID: '|| :new.u_sponsorid);
 15  end;
 16  /

Trigger created.

测试:主行优先:

SQL> insert into u_sponsor values (200);

1 row created.

两个细节:

SQL> insert into user_registration values (100);
insert into user_registration values (100)
            *
ERROR at line 1:
ORA-20010: Not a valid SPONSORID: 100
ORA-06512: at "SCOTT.TRG_IU_SPONSOR", line 10
ORA-04088: error during execution of trigger 'SCOTT.TRG_IU_SPONSOR'


SQL> insert into user_registration values (200);

1 row created.

SQL>

但是,我猜您只是出于教育目的使用触发器来强制执行参照完整性,因为 - 如果您想正确地这样做,请创建外键约束。像这样的:

SQL> create table u_sponsor (u_sponsorid number primary key);

Table created.

SQL> create table user_registration(u_sponsorid number references u_sponsor);

Table created.

SQL> insert into u_sponsor values (200);

1 row created.

SQL> insert into user_registration values (100);
insert into user_registration values (100)
*
ERROR at line 1:
ORA-02291: integrity constraint (SCOTT.SYS_C009854) violated - parent key not found


SQL> insert into user_registration values (200);

1 row created.

SQL>

【讨论】:

我有另一个与此相关的问题:还有另一个表“U_PROJECT”,我还需要在此触发器中同时验证“PROJECTID”并打印消息。 在同一个触发器中包含另一个 SELECT 语句。或者,您可以创建另一个触发器(只是名称不同)。但是,正如我所说,您宁愿创建外键约束,而不是通过触发器强制引用完整性。 这些主表是从 prod 复制到 test Env 的,为了避免主数据安全,建议使用这种触发器。 如果您的数据安全建议使用这种触发器,那么您的数据安全不了解数据库功能。这似乎是一个很大的安全问题。那是建议还是要求? Hey Belayer,没有外键事务表将无法同步数据,因此绝对要求在此基础上,他们建议不要用作主键,只需使用参考检查值扳机。您能否详细说明在这种情况下会出现什么安全问题。

以上是关于ORA-4088、ORA-6512 使用触发器和 RAISE_APPLICATION_ERROR的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL ORA-01422 SELECT INTO 错误,Oracle 匿名块(NOVA 环境)

触发器使用教程和命名规范

触发器使用教程和命名规范

Oracle使用触发器和mysql中使用触发器的比较——学习笔记

如何创建和使用自定义 DataGridRow 触发器

在触发器中声明和使用变量