触发器

Oracle触发器是使用者对Oracle数据库的对象做特定的操作时,触发的一段PL/SQL程序代码,叫做触发器。触发的事件包括对表的DML操作,用户的DDL操作以及数据库事件等。

触发器的作用

Oracle触发器可以根据不同的数据库事件进行特定的调用触发器程序块,因此,它可以帮助开发者完成一些PL/SQL存储过程完成不了的问题,比如操作日志的记录、防止一些无效的操作、校验数据的正确性、限制一些对数据库对象的操作、提供数据同步的可行性。但是不推荐在触发器当中写业务逻辑程序,因为这样对后期数据的维护将大大提高成本。

触发器的类型

触发器按照用户具体的操作事件的类型,可以分为5种触发器。

  • 数据操作DML触发器:此触发器是定义在Oracle表上的,当对表执行insert、update、delete操作时可以触发该触发器。如果按照对表中行级数据进行触发或语句级触发,又可以分为行级(row)触发器,语句级触发器,按照修改数据的前后触发触发器,又可以分为 after 触发器和before触发器之分。

  • 数据定义操作DDL触发器:当对数据库对象进行create、alter、drop操作时,触发触发器进行一些操作记录保存、或者限定操作。

  • 用户和系统事件触发器:该类型的触发器是作用在Oracle数据库系统上,当进行数据库事件时,触发触发器,一般用来记录登录的相关信息。

  • INSTEAD OF 触发器:此类型的触发器是作用在视图上,当用户对视图进行操作时,触发该触发器把相关的操作转换为对表进行操作。

  • 复合触发器:指的是对数据操作(DML)触发器当中的多种类型触发器进行复合,比如;一个触发器当中包含着after(或before)的行级触发器和after(或before)的语句级触发器,来完成一些更为复杂的操作。

例,创建数据校验触发器:

  1. create or replace trigger tr_xsjbxx_insert
  2. before insert on stuinfo
  3. for each row
  4. begin
  5. --对性别的数据进行校验
  6. if :new.SEX not in ('1', '2') then
  7. raise_application_error(-20001, '性别错误,请正确选择。');
  8. end if;
  9. end;
  10. insert into STUINFO
  11. (STUID,
  12. STUNAME,
  13. SEX,
  14. AGE,
  15. CLASSNO,
  16. STUADDRESS,
  17. GRADE,
  18. ENROLDATE,
  19. IDNUMBER)
  20. values
  21. ('SC201801006',
  22. '张三丰',
  23. '3',
  24. 26,
  25. 'C201801',
  26. '福建省厦门市XXX号',
  27. '2018',
  28. to_date('01-09-2018', 'dd-mm-yyyy'),
  29. '3503021992XXXXXXXX');

学生数据插入(insert)之前做的一个性别的校验,当性别的值不符合规范的时候报数据错误。

DML类型触发器

DML类型触发器安装触发的事件的前后和数据触发的类型可以分为四类:前置行级触发器、后置行级触发器、前置语句级触发器、后置语句级触发器。

创建DML类型触发器的语法结构

  1. create [ or replace] trigger tr_name(触发器名)
  2. before|after
  3. delete| insert | update [of column1,column2...]
  4. [or delete |insert| update of colum1,colum2...]
  5. on table_name(表名)
  6. [for each row]
  7. [follows tr_name1(其它触发器名)]
  8. [when 条件]
  9. declare
  10. --声明部分
  11. begin
  12. --触发器内容部分
  13. end;
  • or replace :存在同名的触发器就覆盖保存。
  • trigger:创建触发器的关键词。
  • before|after表示是选择的触发器是数据改变之前触发、数据改变之后触发。
  • delete| insert | update:表示触发器触发的事件类型是删除、插入或更新。
  • for each row: 表示行级触发器、不填就是语句级触发器
  • follows :表示触发器的顺序是跟在哪个之后。
  • when 表示触发器语句触发的条件
行级触发器

例:

  1. create or replace trigger tr_stuinfo_update
  2. before update on stuinfo
  3. for each row
  4. begin
  5. --当学生班号发生变化时,
  6. if :new.CLASSNO <> :old.CLASSNO then
  7. --插入操作日志表
  8. insert into oplog
  9. (LOGID, --日志ID
  10. TABLENAME, --表名
  11. COLNAME, --列名
  12. NEWDATA, --改变后数据
  13. OLDDATA, --改变前数据
  14. OPDATE, --操作时间
  15. OPERATOR) --操作人
  16. values
  17. (pk_oplog_id.nextval,
  18. 'stuinfo',
  19. 'classno',
  20. :new.classno,
  21. :old.classno,
  22. sysdate,
  23. 'jsq');
  24. end if;
  25. end;

这是一个学生信息表(stuinfo)update的前置行级触发器,当修改学生的班号时,会把修改的记录的操作信息记录在日志表(oplog)中。
行级触发器通过:new和:old来访问变化之后的数据和变化之前的数据,update类型触发器,新旧数据都可以访问,delete类型触发器,只能访问:old值,insert类型触发器只能访问:new值。

建立好触发器,我们更改一条数据看下效果,代码如下:

  1. update stuinfo t set t.classno = 'C201802' where t.stuid = 'SC201801006';
  2. select * from oplog;

语句级触发器

语句级触发器一般是用来做特定限制语句操作的作用,比如在某一段时间内禁止某一部分语句操作,下面是一个语句级触发器的案例:
比如今天是12月15号,我就禁止每月的15号禁止操作学生信息表(stuinfo)的插入和删除或修改操作。

  1. create or replace trigger tr_stuinfo_sql
  2. before update or insert or delete on stuinfo
  3. begin
  4. --每月15号禁止操作学生信息表
  5. if to_char(sysdate,'dd')='15' then
  6. raise_application_error(-20001,'每月15号不能对学生信息表进行正删改操作!');
  7. end if;
  8. end;
  • DML语句触发器就是行级触发器省略掉for each row的写法。
  • raise_application_error是主动给客户端抛出-20001代码错误的信息。

建立好触发器,我们更新一条数据看下效果,结果如下:

同一个对象上可以有多个DML触发器,但是触发器触发的时候有先后顺序,比如before型触发器比after型触发器先触发,在此基础上行级触发器,比语句级触发器更早触发。同类型的触发器的先后顺序就按follows关键词+触发器名进行排序。

DDL类型触发器

Oracle DDL类型触发器主要是对于Oracle数据库的DDL操作触发的触发器,主要包括create、drop、alter等DDL事件,经常利用DDL类型触发器记录DDL操作记录或者限定对某个对象进行DDL操作。也可以根据对应DDL操作做对应的操作。

DDL类型触发器的语法结构
  1. create [ or replace] trigger tr_name(触发器名)
  2. before|after
  3. ddl_event|database_event
  4. on SCHEMA(数据库对象)|DATABASE(数据库)
  5. [follows tr_name1(其它触发器名)]
  6. [when 条件]
  7. declare
  8. --声明部分
  9. begin
  10. --触发器内容部分
  11. end;
  • or replace :存在同名的触发器就覆盖保存。
  • trigger:创建触发器的关键词。
  • before|after表示是选择的触发器是在进行DDL操作之前触发还是之后触发。
  • ddl_event:表示的DDL事件,有create(创建)、alter(修改)、drop(删除)等常用DDL操作。
  • SCHEMA|DATABASE:表示触发器是作用在数据库对象上还是数据库上。
  • follows :表示触发器的顺序是跟在哪个之后。
  • when 表示触发器触发的附带条件,比如时间。

例:利用Oracle DDL类型触发器给学生信息表(stuinfo)做一个禁止删除、修改表结构的触发器

  1. create or replace trigger tr_stuinfo_ddl
  2. before alter or drop on schema
  3. begin
  4. --禁止对学生信息表进行删除和修改操作
  5. if dictionary_obj_name = 'STUINFO' THEN
  6. --修改表结构
  7. if sysevent = 'ALTER' then
  8. --抛出错误
  9. raise_application_error(-20001,
  10. '禁止学生信息表stuinfo进行alter操作!');
  11. end if;
  12. --删除表结构
  13. if sysevent = 'DROP' then
  14. --抛出错误
  15. raise_application_error(-20001,
  16. '禁止学生信息表stuinfo进行drop操作!');
  17. end if;
  18. END IF;
  19. end;

我们通过修改学生信息表(stuinfo)测试一下触发器的效果

  1. --修改表结构
  2. alter table STUINFO modify stuaddress VARCHAR2(200);
  3. --删除表结构
  4. drop table stuinfo;

建立DDL类型触发器(数据库级)

利用DDL类型触发器的创建一个数据库级别的触发器,记录用户登录数据库的记录信息。再次我们需要设计一个登录记录表,来保存用户登录信息

  1. -- Create table
  2. create table LOGIN_LOG
  3. (
  4. logid VARCHAR2(20),
  5. loginuser VARCHAR2(100),
  6. logindate DATE
  7. )
  8. tablespace USERS
  9. pctfree 10
  10. initrans 1
  11. maxtrans 255
  12. storage
  13. (
  14. initial 64K
  15. minextents 1
  16. maxextents unlimited
  17. );
  18. -- Add comments to the table
  19. comment on table LOGIN_LOG
  20. is '登录日志表';
  21. -- Add comments to the columns
  22. comment on column LOGIN_LOG.logid
  23. is '日志id';
  24. comment on column LOGIN_LOG.loginuser
  25. is '登录用户名';
  26. comment on column LOGIN_LOG.logindate
  27. is '登入时间';
  1. create or replace trigger tr_stuinfo_ddl_login
  2. after logon--数据库系统事件
  3. on database
  4. begin
  5. --插入登录日志表
  6. insert into login_log
  7. (LOGID, LOGINUSER, LOGINDATE)
  8. values
  9. (pk_oplog_id.nextval,sys.login_user, sysdate);
  10. end;
文档更新时间: 2020-10-20 11:42   作者:张尚