• Oracle数据库之触发器(二)


    DML触发器
    是指在进行insert、update或delete操作时触发的程序体。如果你想在用户对数据进行操作时,记录或限制其操作,就可以用DML触发器。
    举例来说,我想统计我的网站用户的注册、注销或者更新个人信息等情况,我们就可以写如下一个触发器,每当有用户进行上述操作时,触发器会自动执行,并在log日志表中存储这些信息。


    代码:
    create or replace trigger user_log
    before delete or insert or update
    on users
    for each row
    declare
    id number;
    begin
    select count(*)+1 into id from ts_log_users t;
    if inserting then insert into ts_log_users t values (id,sysdate,(select count(*)+1 from ts_log_users t where t.class='create'),'create',:new.username);
    elsif deleting then insert into ts_log_users t values (id,sysdate,(select count(*)-1 from ts_log_users where class='create'),'delete',:new.username);
    else insert into ts_log_users t values (id,sysdate,(select t.count from ts_log_users t where create_date=(select max(t.create_date) from ts_log_users t)),'update',:new.username);
    end if;
    end;



    第一行定义触发器名字为user_log,create or replace意思是建立或如果存在一样名字的触发器则覆盖。

    第二行关键字可以选择before和after,即操作前和操作后。
    比如我想查看用户登录的ip情况,这时我们需要在用户成功登录后触发触发器,所以需写after。
    而这里要对用户的增删改敏感,所以选择before。后面是操作定义,即什么样的操作会触发触发器。

    第三行on后面接表名,即当用户对这个表进行操作时,触发触发器。
    另外,操作为update时,可写成before update of 列名 on 表名,来使限制更加具体化。

    第四行将触发器定义为行级触发器,即每当一行数据发生变化时,就触发一次触发器。
    比如我一下更新了三个用户的信息,那么log日志表中就会生成三条数据。
    如果不写这句话,则触发器只会在上述操作时,触发一次,形成一条数据。

    第五行声明变量,用于存储和操作一些可用数据。

    从begin到end为程序主体,读起来也很容易理解,主要有两个操作,
    一是将log日志的数据量+1作为数据id赋值给之前定义的id变量。赋值用into完成。
    第二个操作是一个if操作,分别完成了对增删改不同情况的处理。
    处理主要为想log日志表插入数据,
    如果是新建用户的话,则向log日志表插入数据id(上面得到的)、系统时间、
    目前用户数量(即count下log日志中是create操作的数据)、
    操作类别(此处为create)以及操作的用户名(:new.的意思就是新修改的数据,对比:old.使用,这两个字段在更新操作时会经常用到。
    例如将更新前的数据插入到另一表中,则用:old.表示,新插入的数据则用:new.操作)。后两个是对delete和update的操作,类似上面不在赘述。



    替代触发器
    这类触发器仅仅应用在视图上。我举个例子就明白这个触发器的用处了。比如说,我提供给初级管理员老张一个视图,只显示用户的基本注册信息,如用户名、性别、民族等,而隐藏了用户密码、身高、体重这些私密信息(这些信息存在表中,老张看不到,因为我没给他看表的权限)。但有一天有个走后门的找老张想把自己的信息加到我数据库中,于是老张就对视图进行插入操作。可是问题来了,当插入一条关系户数据到表中时,我们需要其用户密码、身高体重等(设置了不为空),而老张看不到因此插不进去,因此报错无法操作。所以这时我们就可以写一个替代触发器,即如果老张对视图操作时,后面的表会自动插入一些随机密码等,以完成老张的视图操作。触发器定义格式类似于上面,这里不再赘述(因为我没用视图,所以没写)。



    系统触发器
    是在进行系统操作如startup、drop、alter、logon等时才会触发的。
    下面我写一个,因为我的数据库给了好多人使用,老张、老王等,而他们经常在别的时间和地点登录数据库,我想看看这些登录情况,因此我写一个登录的触发器:

    代码:create or replace trigger oracle_user_log
    after logon
    on database
    declare
    id number;
    begin
    select count(*)+1 into id from ts_o_log_users t;
    insert into ts_o_log_users values (id,sys.login_user,sysdate,ora_client_ip_address);
    end;





    另附一些参考代码:

    create or replace trigger testtrigger
     after insert on test1trige
     for each row
     declare v_flag number:=0;
     begin
     select count(0) into v_flag from test2trige where xh_id = :new.xh;
     if v_flag = 0 then
     insert into test2trige(xh_id,xsxm)  values(:new.xh,:new.xm);
     end if;
     end;
     
     
    create or replace trigger trig_jzg_RYLX after insert or update
    on GXJG_JZGRYLXGX for each row
    declare
      v_sqlerrm varchar(4000);
      v_count_n number:=0;
    begin
       
       select COUNT(0) into V_COUNT_n from bmryxxb@dblink_zfoa  where yhm=:new.yhm and xydm in ('20140503','20140504','20140505','20140506');
       if V_COUNT_n >0 and :new.yhlx not in('009','001') then
           update bmryxxb@dblink_zfoa set  xydm=decode(:new.yhlx,'2','20140503','006','20140504','008','20140505','004','20140506')--,'009','20140503')
                 where yhm=:old.yhm and xydm=decode(:old.yhlx,'2','20140503','006','20140504','008','20140505','004','20140506');   
           update bmryxxb@dblink_zfoa set  xydm=decode(:new.yhlx,'2','20140503','006','20140504','008','20140505','004','20140506')--,'009','20140503')
                 where yhm=:new.yhm and xydm=(select xydm from bmryxxb@dblink_zfoa where yhm=:new.yhm and xydm in ('20140503','20140504','20140505','20140506'));   
        
         --else
           -- insert into bmryxxb@dblink_zfoa
                   -- --  (xydm, jsdm, yhm, sjlsh)
                   -- values
                    --  (decode(:new.yhlx,'2','20140503','006','20140504','008','20140505','004','20140506'), '7', :new.yhm, '1');
       end if;
       
       select COUNT(0) into V_COUNT_n from bmryxxb@dblink_zfoa  where yhm=:new.yhm and xydm in ('20140503','20140504','20140505','20140506');
       if V_COUNT_n =0  then
           insert into bmryxxb@dblink_zfoa
                      (xydm, jsdm, yhm, sjlsh)
                    values
                      (decode(:new.yhlx,'2','20140503','006','20140504','008','20140505','004','20140506'), '7', :new.yhm, '1');
      end if;

       select COUNT(0) into V_COUNT_n from yhb@dblink_zfoa  where yhm=:new.yhm;
       if  V_COUNT_n >0  then
           update yhb@dblink_zfoa set  zdm=decode(:new.yhlx,'2','02','004','05','006','03','008','04','009','01','001','01') where yhm=:old.yhm;
          
       end if;
       
     --异常处理
    Exception
      WHEN OTHERS Then
        v_sqlerrm := (Sqlerrm || chr(10) || dbms_utility.format_error_backtrace);
        Insert Into XT_ERRLOG
        Values
          ('办公系统',
           'bmryxxbrylx',
           'yhm:' || :NEW.yhm,
           v_sqlerrm,
           to_char(sysdate, 'yyyyMMddhh24miss'));
    end;

    ----异常处理表结构

    -- Create table
    create table XT_ERRLOG
    (
      YWXTMC VARCHAR2(100),
      YWXTBM VARCHAR2(100),
      CWZDXX VARCHAR2(500),
      CWSJ   VARCHAR2(1000),
      GXBJ   VARCHAR2(22)
    )
    tablespace ZFDXC
      pctfree 10
      initrans 1
      maxtrans 255
      storage
      (
        initial 448
        next 1
        minextents 1
        maxextents unlimited
      );
    -- Add comments to the table
    comment on table XT_ERRLOG
      is '系统错误日志表';
    -- Add comments to the columns
    comment on column XT_ERRLOG.YWXTMC
      is '业务系统名称(例:数据中心)';
    comment on column XT_ERRLOG.YWXTBM
      is '业务系统表名(例:ZYDMB)';
    comment on column XT_ERRLOG.CWZDXX
      is '显示会导致报错的字段(例如: XH:200010,BJDM:,ZYDM:5200)';
    comment on column XT_ERRLOG.CWSJ
      is '错误时间(例:YYYYMMDDHH24MISS)';
    comment on column XT_ERRLOG.GXBJ
      is '更新标记U/I';

  • 相关阅读:
    Java 序列化和反序列化(三)Serializable 源码分析
    Java 序列化和反序列化(二)Serializable 源码分析
    Java 序列化和反序列化(一)Serializable 使用场景
    JUC源码分析-其它工具类(一)ThreadLocalRandom
    JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor
    JUC源码分析-线程池篇(二)FutureTask
    JUC源码分析-线程池篇(三)Timer
    JUC源码分析-线程池篇(一):ThreadPoolExecutor
    JUC源码分析-集合篇:并发类容器介绍
    JUC源码分析-集合篇(十)LinkedTransferQueue
  • 原文地址:https://www.cnblogs.com/Alanf/p/7614380.html
Copyright © 2020-2023  润新知