zoukankan      html  css  js  c++  java
  • 【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||'123' where 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编程之八:   把触发器说透

  • 相关阅读:
    [Other] 应用下载网站的APK/IPA等常见MIME设置
    [AIR] StageWebView可以和js通信
    [JavaScript] 判断设备类型,加载相应css
    [HTML] H5在webApp中的注意事项
    [JavaScript] css将footer置于页面最底部
    python 装饰器
    python while...else和for...else语法
    Linux haproxy配置参数
    Linux haproxy基础
    Linux ospf+lvs
  • 原文地址:https://www.cnblogs.com/VergiLyn/p/6126748.html
Copyright © 2011-2022 走看看