此行级别触发器失败了什么?

时间:2010-01-21 19:40:59

标签: oracle plsql triggers

我有这个触发器:

create or replace trigger t_calctotal
after insert or update on item_fornecimento
REFERENCING NEW AS NEW OLD AS OLD
for each row

begin

  if inserting then
  dbms_output.put_line(' On Insert');
  update fornecimento f set f.total_enc_fornec = f.total_enc_fornec +:NEW.prec_total_if  where f.id_fornecimento = :NEW.id_fornecimento;

  else
  dbms_output.put_line(' On Update');
  update fornecimento f set f.total_enc_fornec = f.total_enc_fornec - :OLD.prec_total_if +:NEW.prec_total_if  where f.id_fornecimento = :NEW.id_fornecimento;

  end if;

end;

基本上我想通过对item_fornecimento中的所有项目进行求和来刷新订单的总价值(fornecimento);我必须以不同的方式对待它,例如它是一个插入,它是一个更新。 触发器编译,所有甚至工作一次,但它是唯一的。我已经在sqldeveloper中的item_fornecimento中插入或更新了我的prec_total_if,但订单的(fornecimento)总数仍未改变:(。

如果它很重要,我的f.total_enc_fornec它会为null,直到它被这个触发器插入的值替换掉;它打印输出,但似乎无法更新。

2 个答案:

答案 0 :(得分:6)

大家知道:null + 123 = null

我猜这解释了。将总数初始化为0,一切都应该有效。

修改

你可以这样做:

if inserting then
  dbms_output.put_line(' On Insert');
  update fornecimento f set f.total_enc_fornec = nvl(f.total_enc_fornec, 0) +:NEW.prec_total_if  where f.id_fornecimento = :NEW.id_fornecimento;

else
dbms_output.put_line(' On Update');
update fornecimento f set f.total_enc_fornec = nvl(f.total_enc_fornec, 0) - :OLD.prec_total_if +:NEW.prec_total_if  where f.id_fornecimento = :NEW.id_fornecimento;

end if;

答案 1 :(得分:0)

您的触发器将在多用户环境中失败,除非您在父级别实现某种序列化。

如果两个会话大约在同一时间更新item_fornecimento中具有相同id_fornecimento的不同行,则fornecimento.total_enc_fornec将被错误地更新,因为每个会话都不会看到未提交的更改通过其他会议。

要解决此问题,您可能会编写应用程序,以便在更新/插入项目之前尝试对父fornecimento记录进行独占锁定。