首页 > 代码库 > 【database】oracle触发器基础

【database】oracle触发器基础

一、oracle触发器基本语法
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.]table_name | [schema.]view_name
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ]
[WHEN condition]
PL/SQL_BLOCK | CALL procedure_name;

BEFORE: 在执行触发事件前执行触发器内容;

AFTER:在执行触发事件后执行触发器内容;

(貌似还存在第3中:instead of,主要用于视图。待学习....)

FOR EACH ROW: 行级触发器,对应的还有语句级触发器。

  行级触发器,只要数据行符合触发条件,就执行1次触发器;

  语句级触发器,整个语句操作作为触发事件,符合触发条件,则只执行1次触发器;(这个理解还不深刻)

NEW/OLD:只存在与FOR EACH ROW中。且update:NEW、OLD,insert:NEW,delete:OLD;

二、基础demo

说明:当更新子表CHILD的时候,把其对应父表的姓名拼接”123”。

create or replace trigger TEST_TRIGGER
before update ON "CHILD" for each row
declare
  old_age number;
  new_age number;
  v_id number;
  p_id number;
--PRAGMA AUTONOMOUS_TRANSACTION;  -- 自治事务,独立于触发sql的事务
begin
  old_age := :old.child_age;
  new_age := :new.child_age;
  v_id := :new.child_id;
  p_id := :new.parent_id;
  dbms_output.put_line(‘After: old=‘||old_age||‘,new=‘||new_age);
  if 3>2 then
  -- UPDATE CHILD set child_name = child_name||‘123‘ where CHILD_ID = 5;
     UPDATE parent set parent_name = parent_name||‘123where PARENT_ID = p_id;
  --:new.child_name := :old.child_name || ‘123‘;
  dbms_output.put_line(‘if scope!‘);
end if;end TEST_TRIGGER;

奇葩问题: 如果trigger中存在if语法,

  注意demo最后 end if;end TEST_TRIGGER;  如果不这么写(分成2行),此trigger在navicat中编译是通不过的。但在pl/sql中是正确的。

三、trigger的事务、自治事务

  如果trigger不用自治事务,那么触发器的事务和触发触发器事件的事务是同一个。

  我在测试的时候遇到的问题:1、目的:在更新child_age,通过触发器更新其名字child_name。2、因为我要的确实更新后,才更新chile_name,所以我用的BEFORE。

  如果不用自治事务,那么表示触发器和触发事件是处于同一事务(即便是after,触发事件的事务也是没提交的。),oracle是不允许对同一行记录再次进行DML的。

  但是如果使用自治事务,这明显有个问题是,如果触发事件的语句被回滚,那么触发器是确定被触发、且被提交的。所以,此处不能用自治事务(我还真没想到什么场景要用到自治事务)

  如何实现?

  这时就要用到BEFORE/AFTER的区别了,通过前面知道了默认触发器和触发事件是在同一事务。那么可以通过BEFORE达到目的,直接在BEFORE中修改:new对应的字段值。如demo中的:

    :new.child_name := :old.child_name || ‘123‘; 这样,其实就会更新所对应的字段值。

四、备注

  在网上查了下对触发器的看法,发现大部分的观念都不推荐触发器。观点总结:1、触发器性能不好;2、触发器太隐蔽,容易被忽略;3、移植性低,难以维护。

  对于性能,不清楚程度到底怎么样。

  移植性,我接触的项目都不考虑。

  隐蔽性,这很关键,如果项目管理不好。可能都不知道有这个触发器的存在。

  综上,我只能了解到反正大家都不怎么推荐…

  这说下为什么我要用的情况:有张表table_a,存在一个状态位a.status=[1,2,3,4,5,6…];当状态位为[4,5,6]时要给客户发送短信提醒。

  存在的做法:1、在所有代码中,更改status的地方判断,直接调用发送短信(或者把短信放到短信池,定时发送。这有很大却别)。  2、定时器,检测状态位,然后发送。 3、触发器。

  方式1: 我觉得很蠢,你要找到现在有的所有地方。如果后面新增一个地方修改status,别人不一定知道要发短信。(而且还不止这么简单,万一这update被回滚,你直接调短信发送不雪崩?如果是放到短信池还好,都回滚了。)

  方式2: 有一个问题是,你要知道这行数据是不是状态改变过,且是没发送过短信的(麻烦,我没细想这)

  方式3: 触发器,检测行的status,然后符合的insert一条短信到短信池,然后在定时检测短信池发送短信。

附录

 [oracle官方文档 12c]CREATE TRIGGER Statement

  ORACLE PL/SQL编程之八:   把触发器说透

【database】oracle触发器基础