Oracle12--DDL触发器(五十七)
-
DDL触发器的作用
- 定义:当创建,修改,删除数据库对象时,也会引发相应的触发器操作事件,此时可以利用触发器对这些数据库对象的DDL操作进行监控;
- 语法:
CREATE [OR REPLACE] TRIGGER
触发器名称 |
DDL触发器的创建语法中,给出的操作对象有两种: |
-
触发器中支持的DDL事件:
-
在使用以上事件时,想取得一些系统的信息,如当前操作用户,删除的数据库对象等,需要在DBMS_STANDARD包中定义的一些事件属性函数,常用的事件属性函数如下:
- 上表中出现的ORA_NAME_LIST_T是定义在DBMS_STANDARD包中的一个嵌套表类型,定义结构如下:
-
TYPE ora_name_list_t IS TABLE OF VARCHAR2(64); |
- 通过定义发现,该嵌套表中存放的是一个长度为64的字符数据,之后所有返回的数据信息都通过嵌套表取得
-
DDL触发器的使用
-
示例1:禁止c##scott用户的所有DDL操作
-
CREATE OR REPLACE TRIGGER scott_forbid_trigger BEFORE DDL ON SCHEMA BEGIN RAISE_APPLICATION_ERROR(-20007,'scott用户禁止使用任何的DDL操作!') ; END ; / |
该命令会让c##scott用户发出的任何DDL操作抛出异常,并禁止操作 |
删除此触发器: |
示例2:使用日志来记录数据库对象的操作
- 数据库对象操作日志记录表创建脚本
DROP TABLE object_log PURGE ; DROP SEQUENCE object_log_seq ; CREATE SEQUENCE object_log_seq ; CREATE TABLE object_log ( oid NUMBER CONSTRAINT pk_oid PRIMARY KEY, username VARCHAR2(50) NOT NULL , operatedate DATE NOT NULL , objecttype VARCHAR2(50) NOT NULL , objectowner VARCHAR2(50) NOT NULL ) ; |
此日志表,oid使用序列(object_log_seq)自动生成,操作日期通过SYSDATE取得,其他的字段使用事件属性取得 |
- 编写触发器实现对数据库对象操作的日志记录
CREATE OR REPLACE TRIGGER object_trigger AFTER CREATE OR DROP OR ALTER ON DATABASE DECLARE BEGIN INSERT INTO c##scott.object_log(oid,username,operatedate,objecttype,objectowner) VALUES (c##scott.object_log_seq.nextval,ORA_LOGIN_USER, SYSDATE,ORA_DICT_OBJ_TYPE,ORA_DICT_OBJ_OWNER) ; END ; / |
在本触发器中,每当发生了对象的创建,删除,修改操作之后,都会自动向object_log数据表中添加相应的记录 |
-
综合示例
- 需求:禁止修改emp数据表的empno(主键)列和deptno(外键)列的定义结构;
-
分析:
- 如果要对修改表结构的操作进行触发,则需要使用ALTER事件操作,而且应该选择更新前触发;
- 在每次修改表结构的操作中,需要取出一张数据表的所有列来判断其是否被修改,而要想取出一张表中的所有数据列,可以使用all_tab_columns数据字典来查询;
- 步骤1:查询c##scott.emp表,验证该数据字典;
SELECT * FROM all_tab_columns WHERE table_name='EMP' AND owner='C##SCOTT'; |
-
分析:
- 如果要把全部的列信息依次进行判断,则需要采用游标的方式来进行处理。使用取得指定查询的所有数据行(每一行是表中一个列的信息),而后使用ORA_IS_LATER_COLUMN和ORA_IS_DROP_COLUMN事件属性判断当前修改列或删除列的名字是否为empno或deptno,如果是,则抛出一个异常;
- 为了保证此操作可以对当前用户使用,可以定义一个参数游标,通过ORA_DICT_OBJ_OWNER取得操作表的用户,通过ORA_DICT_OBJ_NAME取得操作数据表名称;
-
步骤2:在c##scott用户中定义参数游标
CREATE OR REPLACE TRIGGER emp_alter_trigger BEFORE ALTER ON SCHEMA DECLARE --操作的所有者以及操作的表名称由外部传递 CURSOR emp_column_cur(p_tableOwner all_tab_columns.owner%TYPE , p_tableName all_tab_columns.table_name%TYPE) IS SELECT column_name FROM all_tab_columns WHERE owner=p_tableOwner AND table_name=p_tableName ; BEGIN IF ORA_DICT_OBJ_TYPE = 'TABLE' THEN-- 如果操作的是数据表 FOR empColumnRow IN emp_column_cur(ORA_DICT_OBJ_OWNER , ORA_DICT_OBJ_NAME) LOOP IF ORA_IS_ALTER_COLUMN(empColumnRow.column_name) THEN -- empno字段要被修改 IF empColumnRow.column_name = 'EMPNO' THEN RAISE_APPLICATION_ERROR(-20007,'empno字段不允许修改!') ; END IF ; -- deptno字段要被修改 IF empColumnRow.column_name = 'DEPTNO' THEN RAISE_APPLICATION_ERROR(-20008,'deptno字段不允许修改!') ; END IF ; END IF ; IF ORA_IS_DROP_COLUMN(empColumnRow.column_name) THEN -- empno字段要被删除 IF empColumnRow.column_name = 'EMPNO' THEN RAISE_APPLICATION_ERROR(-20009,'empno字段不允许删除!') ; END IF ; -- deptno字段要被删除 IF empColumnRow.column_name = 'DEPTNO' THEN RAISE_APPLICATION_ERROR(-20010,'deptno字段不允许删除!') ; END IF ; END IF ; END LOOP ; END IF ; END ; / |
本程序创建了一个参数游标,分别接收对象的所有者,操作对象名称。之后在使用游标循坏找到操作时,通过两个事件属性将当前操作的用户及对象名称传递到参数游标之内。 |
-
步骤3:创建完触发器之后,下面对emp表中的empno或deptno字段进行修改或删除操作
-
修改empno字段
-
ALTER TABLE emp MODIFY (empno NUMBER(6)) ; |
-
删除deptno字段
ALTER TABLE emp DROP COLUMN deptno ; |