trigger 错误ORA-04084 ORA-04088

这篇博客详细介绍了在Oracle中遇到的触发器错误,包括ORA-04084(无法更改此触发器类型的NEW值)和ORA-04091(变异表错误)。文章通过示例代码解释了这两个错误产生的原因,并提供了相应的解决建议,即避免在‘after’触发器中修改NEW值,以及理解并防止在触发器中查询或修改正被操作的表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

错误trigger code
CREATE OR REPLACE TRIGGER trig_usernumber_insert_dxdss after insert on dxdss
referencing old as old_value new as new_value for each row
declare
v_curr_size integer;
v_has number;
v_sql varchar2(128);
v_num varchar2(33);
p_nError NUMBER;
p_userID NUMBER;
p_vaddusID NUMBER;
p_dxhfsID NUMBER;
p_dxhfsSID NUMBER;
p_dxhfsWID NUMBER;
p_dxhfsBID NUMBER;
V_ERROR_MESSAGE VARCHAR2(500);
begin
select count(*) into v_has from DXBG_MAIL_BOX_COUNT where usernumber=:new_value.USERNUMBER;
if(v_has =0) then
[color=red]select count(*) into v_curr_size from DXdss where usernumber=:new_value.USERNUMBER;[/color] insert into DXBG_MAIL_BOX_COUNT (USERNUMBER,BOX_CURR_SIZE) values (:new_value.USERNUMBER,v_curr_size);
elsif(v_has =1) then
[color=red]select BOX_CURR_SIZE into v_curr_size from DXBG_MAIL_BOX_COUNT where usernumber=:new_value.USERNUMBER;[/color]
v_curr_size:=v_curr_size+1;
update DXBG_MAIL_BOX_COUNT set BOX_CURR_SIZE=v_curr_size where usernumber=:new_value.USERNUMBER;
else
[color=red]select count(*) into v_curr_size from DXdss where usernumber=:new_value.USERNUMBER;[/color]
delete from DXBG_MAIL_BOX_COUNT where usernumber=:new_value.USERNUMBER;
insert into DXBG_MAIL_BOX_COUNT (USERNUMBER,BOX_CURR_SIZE) values (:new_value.USERNUMBER,v_curr_size);
end if;
EXCEPTION
when others then
p_nError := SQLCODE;
V_ERROR_MESSAGE := sqlerrm;
insert into HISTORYOAMALERT (ALERTTYPE, ALERTTIME, ALERTFROM, COMPUTER, ALERTLEVEL, DESCRIPTION)
values('ORACLE',TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS'),'ORACLE','DB','1',p_nError||' '||V_ERROR_MESSAGE);
RAISE;

END;
ORA-04091 table string.string is mutating, trigger/function may not see it

Cause: A trigger (or a user defined PL/SQL function that is referenced in this statement) attempted to look at (or modify) a table that was in the middle of being modified by the statement which fired it.

Action: Rewrite the trigger (or function) so it does not read that table.

ORA-06512 at string line string

Cause: Backtrace message as the stack is unwound by unhandled exceptions.

Action: Fix the problem causing the exception or write an exception handler for this condition. Or you may need to contact your application administrator or database administrator.

ORA-04088 error during execution of trigger 'string.string'

Cause: A runtime error occurred during execution of a trigger.

解释:
变异表是一个当前正在改变的表。改变可以是因为INSERT、UPDATE或DELETE语句,或者由于DELETE CASCADE约束。

这种错误类型只会在行级触发器上发生。

当表在改变时,不能对表进行查询或修改。细想一下就会发现它是有意义的。如果触发器因为表上的改变而激发,那么直到结束之前都看不到这种改变。尽管可以访问new和old伪记录,但是不能读取表的状态。任何这么做的企图都会引发ORA-04091异常。

下面演示了变异错误的发生过程。按照如下代码所示创建一个mutant表:

CREATE TABLE mutant

( mutant_id NUMBER

, mutant_name VARCHAR2(20));

然后可以插入4个主要“忍者神龟”:

INSERT INTO mutant VALUES (mutant_s1.nextval,'Donatello');

INSERT INTO mutant VALUES (mutant_s1.nextval,'Leonardo');

INSERT INTO mutant VALUES (mutant_s1.nextval,'Michelangelo');

INSERT INTO mutant VALUES (mutant_s1.nextval,'Raphael');

插入数据以后,可以构建下面的触发器:

CREATE OR REPLACE TRIGGER mutator

AFTER DELETE ON mutant

FOR EACH ROW

DECLARE

rows NUMBER;

BEGIN

SELECT COUNT(*) INTO rows FROM mutant;

dbms_output.put_line('[rows] has '||rows||']');

END;

/

触发器主体试图得到行数,但是它得不到行数,因为记录集没有结束。存在这个限制是为了防止触发器看到不一致的数据。

可以通过运行下面的命令删除变异表中的Michelangelo来激发触发器。DELETE语句为:

DELETE FROM MUTANT WHERE mutant_name = 'Michelangelo';

运行了该语句后,DELETE语句会抛出下面的错误堆栈:

DELETE FROM mutant WHERE mutant_name = 'Michelangelo'

ERROR at line 1:

ORA-04091: table PLSQL.MUTANT is mutating, trigger/function may not see it

ORA-06512: at "PLSQL.MUTATOR", line 4

ORA-04088: error during execution of trigger 'PLSQL.MUTATOR'

当触发器遇到变异表时,它会回滚触发器主体指令和触发语句。知道了为什么会生生变异表错误,就应当小心地避免这种错误。


错误的触发器code:
CREATE OR REPLACE TRIGGER trig_dxbg_count_insert [color=red]after [/color]insert on DXBG_MAIL_BOX_COUNT
referencing old as old_value new as new_value FOR EACH ROW
declare
v_curr_size integer;
v_has number;
v_boxid VARCHAR2(32);
v_box VARCHAR2(32);
v_sql VARCHAR2(128);
p_nError NUMBER;
V_ERROR_MESSAGE VARCHAR2(500);
begin
v_boxid:=SUBSTR((:new_value.USERNUMBER),10);
v_box:='DXBG_MAIL_BOX_'||v_boxid;
v_sql:='select count(*) from '||v_box||' where usernumber='||:new_value.USERNUMBER;
execute immediate v_sql into v_curr_size;
:new_value.BOX_CURR_SIZE:=v_curr_size;
EXCEPTION
when others then
p_nError := SQLCODE;
V_ERROR_MESSAGE := sqlerrm;
insert into HISTORYOAMALERT (ALERTTYPE, ALERTTIME, ALERTFROM, COMPUTER, ALERTLEVEL, DESCRIPTION)
values('ORACLE',TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS'),'ORACLE','DB','1',p_nError||' '||V_ERROR_MESSAGE);
RAISE;

END;
/

执行报错,错误信息:ORA-04084 无法更改此触发器类型的NEW值

New trigger variables can only be changed in before row insert or update triggers.

把触发器的after改成before 触发
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值