第十五章:触发器

目录

一、 DDL触发器

二、DML触发器

三、INSTEAD OF 触发器

四、系统触发器


什么是触发器?

触发器是指存放在数据库中,并且被隐含执行的存储过程。当发生特定事件时,Oracle会自动执行触发器的相应代码。

SQL> --当我们对empnew执行删除操作之后,它就会出现一个提示信息,提示:这是删除操作!
SQL> CREATE TRIGGER first_trigger
  2  AFTER DELETE
  3  ON empnew
  4  BEGIN
  5     DBMS_OUTPUT.put_line('这是删除的操作!');
  6  END;
  7  /
Trigger created

SQL> SET SERVEROUTPUT ON
SQL> DELETE FROM empnew WHERE empno = 7788;
这是删除的操作!
1 row deleted

一、 DDL触发器

当创建、修改或者删除数据库对象操作时,也会引起相应的触发器操作事件,而此时就可以利用触发器来对这些数据库对象的DDL操作进行监控。

RAISE_APPLICATION_ERROR(error_number_in IN NUMBER,error_msg_in IN VARCHAR2):用来测试的异常处理。将应用程序专有的错误从服务器端转达到客户端应用程序(其他机器上的SQLPLUS或者其他前台开发语言)。

  • error_number_in只容许从-20000到-20999之间。
  • error_msg_in的长度不能超过2k。
--案例1:禁止SCOTT用户的DDL操作
CREATE OR REPLACE TRIGGER scott_trigger
BEFORE DDL
ON SCHEMA
BEGIN
   RAISE_APPLICATION_ERROR(-20005,'scott用户禁止所有的DDL操作!');
END;

--测试
CREATE SEQUENCE test_seq;

DDL触发器事件的属性函数:

  • ORA_DICT_OBJ_OWNER触发DDL的数据库对象的用户
  • ORA_DICT_OBJ_TYPE触发DDL的数据库对象的类型
--案例2:
--创建一个记录数据库对象DDL操作的日志表
create table object_log(
       logid number constraint pk_logid primary key,       
       operatedate date not null,
       objecttype varchar2(50) not null,
       objectowner varchar2(50) not null
);

CREATE SEQUENCE object_log_seq;

--创建触发实现对数据库对象DDL操作记录的触发器
CREATE OR REPLACE TRIGGER object_trigger
AFTER CREATE OR DROP OR ALTER
ON DATABASE
BEGIN
  INSERT INTO object_log(logid,operatedate,objecttype,objectowner)
  VALUES(object_log_seq.nextval,sysdate,ORA_DICT_OBJ_TYPE,ORA_DICT_OBJ_OWNER);
END;

--测试
conn yanln/yanln
create sequence test_seq1;

conn system/password
select * from object_log;

二、DML触发器

DML触发器是指基于DML操作所建立的触发器。可用于实现数据安全保护、数据审计、数据完整性、参照完整性、数据复制等功能。

DML触发器的类型:

  • 语句触发器:在指定的操作语句之前或之后执行一次,不管这条语句影响了多少行。
  • 行触发器:触发语句作用的每一条记录都被触发,在行级触发器中使用:old和:new伪记录变量,识别值的状态。
  1. :old:表示操作该行之前,这一行的值。
  2. :new:表示操作该行之后,这一行的值。
--开发示例1(语句级触发器)

SQL> CREATE OR REPLACE TRIGGER emp_trigger1
  2  BEFORE INSERT OR UPDATE OR DELETE
  3  ON emp
  4  BEGIN
  5     IF to_char(sysdate,'day') IN ('星期六','星期日')THEN
  6        RAISE_APPLICATION_ERROR(-20006,'不能在休息日改变员工信息!');
  7     END IF;
  8  END;
  9  /
Trigger created

SQL> delete from emp where empno = 7788;
delete from emp where empno = 7788
ORA-20006: 不能在休息日改变员工信息!
ORA-06512: 在 "SCOTT.EMP_TRIGGER1", line 3
ORA-04088: 触发器 'SCOTT.EMP_TRIGGER1' 执行过程中出错


--开发示例2

--创建审计表
CREATE TABLE delete_emp_audit(
       name VARCHAR2(10),
       delete_time DATE
);

--创建触发器
CREATE OR REPLACE TRIGGER del_emp_trigger
AFTER DELETE ON emp
FOR EACH ROW
BEGIN
  INSERT INTO delete_emp_audit VALUES(:old.ename,SYSDATE);
END;

--测试
DELETE FROM emp WHERE empno = 7499;

select * from delete_emp_audit;

--开发示例3
SQL> CREATE OR REPLACE TRIGGER tr_check_sal
  2  BEFORE UPDATE OF sal ON emp
  3  FOR EACH ROW
  4  WHEN (new.salold.sal*1.5)
  5  BEGIN
  6       RAISE_APPLICATION_ERROR(-20028,'工资只升不降,并且升幅不能超过50%');
  7  END;
  8  /
Trigger created

SQL> UPDATE emp SET sal = sal*1.8 WHERE empno = 7788;
UPDATE emp SET sal = sal*1.8 WHERE empno = 7788
ORA-20028: 工资只升不降,并且升幅不能超过50%
ORA-06512: 在 "SCOTT.TR_CHECK_SAL", line 2
ORA-04088: 触发器 'SCOTT.TR_CHECK_SAL' 执行过程中出错


--开发示例4
CREATE OR REPLACE TRIGGER upd_cascade_trigger
AFTER UPDATE OF deptno
ON dept
FOR EACH ROW
BEGIN
  UPDATE emp SET deptno = :new.deptno WHERE deptno = :old.deptno;
END;

--测试
UPDATE dept SET deptno = 50 WHERE deptno = 10;

select deptno,ename from emp where deptno = 50;

三、INSTEAD OF 触发器

替代触发器是适用于视图上的一种触发器。在简单试图上往往可以执行insert、update、delete操作,但在复杂视图上执行insert、update、delete操作是有限制的

替代触发器的限制:

  • 只适用于视图
  • 不能指定before和after选项
  • 不能在具有with check option选项的视图上建立替代触发器
  • 必须包含for each row选项
--创建视图
CREATE OR REPLACE VIEW emp_dept
AS
SELECT d.deptno,d.dname,e.empno,e.ename
FROM dept d, emp e
WHERE d.deptno = e.deptno;


--创建替代触发器
CREATE OR REPLACE TRIGGER instead_of_trigger
INSTEAD OF
INSERT
ON emp_dept
FOR EACH ROW
DECLARE
    v_temp INT;
BEGIN
    SELECT COUNT(*) INTO v_temp FROM dept WHERE deptno = :new.deptno;
    IF v_temp = 0 THEN
       INSERT INTO dept(deptno,dname)VALUES(:new.deptno,:new.dname);
    END IF;
    SELECT COUNT(*) INTO v_temp FROM emp WHERE empno = :new.empno;
    IF v_temp = 0 THEN
       INSERT INTO emp(empno,ename,deptno) VALUES(:new.empno,:new.ename,:new.deptno);
    END IF;
END;

--测试
INSERT INTO emp_dept VALUES(50,'DEVELOPMENT',2222,'ALICE');

SELECT * FROM EMP_DEPT

四、系统触发器

由特定系统事件所触发的触发器。系统事件是指与例程或方案相关的数据库事件,它包括:

  • STARTUP:启动数据库后触发
  • SHUTDOWN:关闭数据库之前触发
  • DB_ROLE_CHANGE:改变角色后第一次打开数据库时触发
  • SERVERERROR:发生Oracle错误时触发
--连接sys用户


--创建事件表
CREATE   TABLE   event_table(
  event varchar2(50), 
  event_time date
);

--再创建一个系统触发器
create or replace trigger startup_trigger
after startup on database
begin
  insert into event_table values(ora_sysevent,SYSDATE);
end;


--在SQLPLUS窗口执行下列命令
SHUTDOWN
STARTUP
SELECT    *   FROM event_table;

 

你可能感兴趣的:(Oracle入门)