zoukankan      html  css  js  c++  java
  • |转|oracle 触发器开发

    转发http://blog.csdn.net/cdl2008sky/article/details/5129589

    触发器开发的目的:确保数据库满足特定的商业规则和企业逻辑,可以使用触发器,约束,子程序。因为
       约束最简单且性能好,所选约束,如果约束不能满足,就用触发器,若触发器都不能满足选择子程序。
       
       一、触发器功能:
       1,控制数据安全,在服务器级别控制数据安全是通过授权和回收对象权限来完成的,比如ams用户对scott/tiger 用户对表DML 操作、
       grant select ,delete,update,insert on emp to ams;
       但是为了实现更复杂的安全模式,比如限制对某个表要修改的数据,就需要用到触发器,比如,只有在9:00到17:00才能改变数据库EMP表对数据库表操作
       create or replace trigger triger_stat_before
        before insert or update or delete on emp
        
        declare
        -- local variables here
        begin
         if (to_char(sysdate,'HH24') not between '9' and '17') then
           RAISE_APPLICATION_ERROR(-20101,'非工作日时间');
         end if;
       end triger_before;


       2,实现数据审计,监视非法和可疑的数据活动,oracle 本身提供了审计功能。如对emp DML 操作以后,
       把SQL操作的信息(用户,时间等)写入字典。但是只能审计sql 操作,不能记载数据变化。如果要记载数据
       变化必须使用DML触发器。比如工资变化写入数据字典表。
       --创建字典表
          drop table EMP_CHANGE;
       create table EMP_CHANGE(
        CNAME       VARCHAR2(200),
        OLDSAL      NUMBER,
        NEWSAL      NUMBER,
        CHANGE_TIME TIMESTAMP(6)
       )
      --创建触发器
      create or replace trigger triger_row_after
       after update of sal  on emp  
       for each row 
       declare
       -- local variables here
       v_temp number;
       begin
        select count(*) into v_temp from emp_change where emp_change.cname=:old.ename;
        if v_temp =0 then
         insert into emp_change values(:old.ename,:old.sal,:new.sal,sysdate);
        else 
         update  emp_change set oldSal=:old.sal,newSal=:new.sal,change_time = sysdate
         where emp_change.cname = :old.ename;
        end if;
      end triger_row_after;
       
       执行sql:update emp set sal = sal*1 where deptno=30
       会把员工的工资变化情况写入emp_change表


       3,实现数据完整性,有写check 做不到的时候就要触发器,比如新工资不能低于原来的工资也不能高于原来工资的20%。
      create or replace trigger triger_row_before
       before update of sal on emp  
       for each row
       when (new.sal <old.sal or new.sal >old.sal*1.2)
       declare
       -- local variables here
       begin
        raise_application_error(-20931,'新工资不能低于原来的工资,并且涨幅不能高于20%');
      end triger_row_before;
       执行sql: update emp set sal = sal*0.3 where deptno=30
       会报错:新工资不能低于原来的工资,并且涨幅不能高于20%


       4,实现参照完整性,参照完整性是指两个表有关联关系,主外键关系,当删除主表数据时,从表数据也对应被删除
       修改主表的主键列数据时,会级联更新从表相关数据列被修改。级联删除可以通过约束 on delete cascade 关键字
       alert table emp add constraint fk_deptno foreign key(deptno) references dept(deptno) on delete cascade;
       但是不能实现级联更新。
       如:update dept set dept.deptno=50 where dept.deptno=20
       违法约束条件,已经找到子记录
       触发器可以实现级联更新功能。
      create or replace trigger triger_up_casecade
       after update of deptno on dept  
       for each row
       declare
       -- local variables here
       begin
        update emp set emp.deptno=:new.deptno where emp.deptno = :old.deptno;
      end triger_up_casecade;
      执行sql:update dept set dept.deptno =50 where dept.deptno =10
      级联更新了emp 表里原来部门号为10的员工部门号为50.
      
       二、触发器是被隐含执行的存储过程,允许基于表和试图的DML操作和基于系统事件(启用数据库,关闭数据库,登录)
       1)各种DML触发器:
         触发器组成:触发器事件,触发器条件和触发器操作三部分组成
        a 触发事件是指引起触发器被触发的sql,数据库事件,用户事件,具体如下
         启动关闭例程
         oracle 错误消息
         用户登录和断开会话
         表或者视图上的DML 操作
         任何方案上的DDL操作
        b 触发器条件是指where子句指定一个表达式
        c 触发器操作是指执行sql语句或者pl/sql块
        
      重点是DML触发器。
      触发时机  before 表示在在执行DML操作之前触发触发器,after 表示在在执行DML操作之后触发触发器
      触发类型  触发事件发生以后,需要执行几次触发操作,如果语句触发器(默认),只会执行一次触发代码
      如果指定行触发类型,则会在每个被作用行上执行一次触发器代码。
      注意:
      对于oracle行级触发器(for each row),不能对本表做任何操作,包括读取 
      原则:    就是为了防止脏读  
      在before   insert触发器中,可以实现对本表的访问;   
      在after   insert触发器中,不能实现对本表的访问;   
      在before/after   update/delete触发器中,都不能实现对本表的访问。 
      
      语句触发器主要用在审计DML操作或者确保DML操作安全执行时,可以使用语句触发器,如:对一个员工表更新之前
      检查当前日期是不是周六,或者周日,如果是不能更新。
      
      before 语句触发器:确保DML语句在正常情况下执行
      after  语句触发器:审计DML操作,或者在DML操作以后进行汇总操作
      before 行触发器:确保数据符合逻辑,使用约束对输入条件加以限制,比如员工新工资不能低于原来的工资
      after  行触发器:审计数据变化,比如一个员工工资变化了,把变化了的员工信息写入审计表
      
      限制行触发器:就是在行触发器中,并不是对所有行都触发而是加了条件,格式
      create or replace trigger triger_test
      before  update or delete on trigger_tab  
      for each row --行触发器都的加上这个语句
      where (:old.name='chen')
      declare
      v_name varchar2(200);
      begin
      end;
       
      RAISE_APPLICATION_ERROR 方法介绍:  
      里面的错误代码和内容,都是自定义的。说明是自定义,当然就不是系统中已经命名存在的错误类别,是属于一种自定义事务错误类型,才调用此函数。
      error_number_in 之容许从 -20000 到 -20999 之间,这样就不会与 ORACLE 的任何错误代码发生冲突。
      error_msg_in 的长度不能超过 2K,否则截取 2K。
      
      :old.name和:new.name 介绍
      :new.value是name的新值。
      :old.value是name修改前的值。
      :old只对Update或者Delete有,对Insert来说,其之前没有数据,所以只能用:new  
      当在trigges 体引用old 和new,必须加前缀:,和绑定变量的时候一样,申明部分不需要。
      
      sql脚本
      create table trigger_tab(
       userID number not null primary key,
       userName varchar2(200),
       age number,
       address varchar2(200)
      )
      insert into trigger_tab(userID,userName,age,address) values(1,'chen',20,'茶陵');
      insert into trigger_tab(userID,userName,age,address) values(2,'li',15,'悠闲');
      insert into trigger_tab(userID,userName,age,address) values(3,'zh',29,'北京');


      创建触发器
      create or replace trigger triger_test
        before  update or delete on trigger_tab  
        for each row --行触发器都的加上这个语句
      declare
        -- local variables here
      begin
        if(:new.age<18)then --:old.age 是更新记录前的值, :new.age是记录更新后的值
            RAISE_APPLICATION_ERROR(-20001,'年龄小于18岁,不能删除和修改'); 
        end if;
      end triger_test;


      command window 窗口执行sql
      update trigger_tab t  set t.address='长沙' where t.username='li';
      后台打印
      ORA-20000: 年龄小于18岁,不能修改和删除
      ORA-06512: 在"SCOTT.TRIGER_TEST", line 5
      ORA-04088: 触发器 'SCOTT.TRIGER_TEST' 执行过程中出错

      java 中调用
      public class TestTriger {
       public static void main(String []args){
        String sqlStr = "update trigger_tab t  set t.address='长沙' where t.username='li'";
        Connection conn = Connector.getConn();
        PreparedStatement pstmt;
        try {
         pstmt = conn.prepareStatement(sqlStr);
         int rowNum = pstmt.executeUpdate();
        } catch (SQLException e) {
         if(e.getErrorCode()==20001){
          String errorM = e.getMessage();
          System.out.println(errorM);
          System.out.println(errorM.split("ORA")[1].replace("-"+e.getErrorCode()+":", ""));
         }
        }
       }
      }
      捕获到的异常都一个异常Code,这个code 就是在RAISE_APPLICATION_ERROR(-20001,'年龄小于18岁,不能删除和修改');
      设置的-20001,去掉前面的负号。
      异常信息得到
      ORA-20000: 年龄小于18岁,不能修改和删除和修改
      ORA-06512: 在"SCOTT.TRIGER_TEST", line 5
      ORA-04088: 触发器 'SCOTT.TRIGER_TEST' 执行过程中出错
      格式化以后就是想到得到的异常信息了,"年龄小于18岁,不能修改和删除和修改"。

  • 相关阅读:
    Linux kernel device mapper
    草莓网
    openwrt系统源码地址
    ubuntu 安装eclipse for c++
    ubuntu下安装eclipse IDE for C/C++ developers
    Makefile 中:= ?= += =的区别
    core dump
    rtp
    skbuff
    A Neural Algorithm of Artistic Style
  • 原文地址:https://www.cnblogs.com/sumsen/p/2524845.html
Copyright © 2011-2022 走看看