Oracle--触发器
触发器
特殊的存储过程, 不需要我们手动调用, 当用户触发某一个行为, Oracle自动执行相对于的触发器
触发器的语法: trigger
CREATE [OR REPLACE] TRIGGER 触发器名 触发时间 触发事件 [ON表名/视图名] [FOR EACH ROW] [when 条件] //加上FOR EACH ROW 即为行级触发器,不加时为语句级触发器 DECLARE 声明部分 BEGIN pl/sql语句 END;
注意:
-- 1) 触发时间:即该触发器是在触发事件发生之前(BEFORE)还是之后(AFTER)触发, instead of替换,只用于视图 ,用的很少. -- 2) 触发事件: 某个动作: 可以写多个 -- DML触发: insert, update,delete *** -- DDL触发: cretae alter drop *** -- 系统事件: oracle服务系统的启动, 关闭,异常 -- 用户事件: 登录, 退出 -- 3)触发条件:由WHEN子句指定一个逻辑表达式。只有当该表达式的值为TRUE时,遇到触发事件才会自动执行触发操作。 -- 4) 触发频率: FOR EACH ROW: 行级触发, 操作每一行,都触发, 没有加: 语义级触发, 只触发一次
注意: 在oracle规定: 在触发器中不能提交(commit)/回滚(rollback)事务
原因:oracle把触发器当成后台监控,而我们的commit/rollback是前台监控
所以你不能用后台来操控前台的操作.
语义级触发器:例:
-- 编写一个针对于emp_back3 进行删除操作的触发器 create or replace trigger trig_deleteEmp after delete on emp_back3 declare begin dbms_output.put_line('删除了数据'); end; --执行 --删除 delete emp_back3 where deptno = 20;
行级触发器:例:
--行级触发器 for each row create or replace trigger trig_deleteEmp after delete on emp_back3 for each row declare begin dbms_output.put_line('删除了数据'); end; drop trigger trig_deleteEmp; --执行 --删除 delete emp_back3 where deptno = 20;
触发器的一些操作
--查看当前用户创建哪些触发器 select * from user_triggers; --查看某个触发器的源代码 select * from user_source where name ='TRIG_EMP2_UPDATE'; --禁用触发器 alter trigger 触发器名 disable alter trigger TRIG_EMP2_UPDATE disable; --启动触发器 alter trigger 触发器名 enable alter trigger TRIG_EMP2_UPDATE enable; --启动某张表中定义所有的触发器 alter table emp2 enable all triggers; --禁用某张表中定义的所有触发器 alter table emp2 disable all triggers; --删除触发器 drop trigger TRIG_EMP2_UPDATE;
触发器的谓词
inserting, deleting, updating --如果一个触发绑定多个事件, 想知道 触发这个触发器由哪个事件触发 --通过谓词来判断,
--如果是insert事件触发, inserting谓词的值为true --如果是delete事件触发, deleting谓词的值为true --如果是update事件触发, updating谓词的值为true
例:
create or replace trigger trig1 after insert or delete or update on emp_back3 declare begin if inserting then --如果是插入, 打印 insert table dbms_output.put_line(' insert table'); -- 调用dbms_output包下的put_line() 存储过程 elsif deleting then --如果是删除, 打印 delete table dbms_output.put_line(' delete table'); elsif updating then --如果是修改, 打印 update table dbms_output.put_line(' update table'); end if; end; insert into emp_back3 values(1010,'JIM','ANALYST',7566,sysdate,4500,null,20); delete from emp_back3 where empno = 1010; update emp_back3 set sal = sal + 2;
伪记录
:new 新的记录, :old 旧的记录 ***伪记录 只能在行级触发器有效 -- insert操作: 只有 :new -- delete操作: 只有 :old -- update操作: 有:new :old
例: 加薪, 不能加倒薪, 抛异常(自定义错误异常), oracle 会捕获的
create or replace trigger trig2 after update on emp_back3 for each row --when 条件 declare begin if :old.sal > :new.sal then -- 学习oracle提供的一种抛异常的方式: 这个异常会被Oracle进行捕获 -- 自定义的错误代码: -20000~-20999 -- raise_application_error(错误代码, 错误信息); raise_application_error(-20001,'不能加倒薪'); end if; end; -- 执行 begin update emp_back3 set sal = sal - 1 where empno = 1001; commit; exception when others then dbms_output.put_line('出错了...'); rollback; end;
触发器的条件when
/* 在Oracle触发器中,可以使用when关键字来指定触发器触发的条件,条件触发器不仅仅要满足触发事件,而且还有满足触发条件. 注意: 1.when 只能在行级触发器中使用. 2.when中使用伪记录(new,old)时不需要加: */
例:
--只有更新后的工资大于更新前的薪水 ,则打印update add create or replace trigger trig_emp after update on emp_back3 for each row --更新后的工资大于更新前的薪水,when中伪记录不需要加 : when (new.sal >old.sal ) begin dbms_output.put_line('update ok'); end; --修改 update emp_back3 set sal = sal + 1 where empno = 1001;
DDL触发器
-- 语法: create [or replace ] trigger 触发器名 {before/after} {create/drop/alter}--触发事件可以多个 on database --注意此时的触发不再对某张表的数据 [when 条件] declare begin --执行语句 end
读取DDL事件属性
sysevent -->事件
dictionary_obj_type :-->对象类型,如表
dictionary_obj_name -->对象名称:如表名
dictionary_obj_owner -->拥有者
user --> 获取当前登录的用户名
触发器 对数据库所有的用户都有效
是system用户创建
例:创建一个日志表
create or replace trigger trig_logRecode after create or alter or drop on database declare --创建变量来接收 v_action varchar2(50); v_type varchar2(50); v_name varchar2(50); begin --给变量赋值 v_action := sysevent; v_type := dictionary_obj_type; v_name := dictionary_obj_name; --往 tb_recode 插入数据 insert into tb_record values(seq_record_id.nextval,user,v_type,v_name ,v_action,default); --触发器,自动提交, 不能手动提交 dbms_output.put_line('日志添加成功!!'); end; -- tb_record 在system用户下 select * from tb_record;
用户事件:
-- 用户登录退出日志表 create table userlog ( username varchar2(20), logon_time date ); --logon登录操作 create or replace trigger database_logon after logon on database --登录数据库后触发 begin insert into userlog values(user,sysdate); -- commit; end; --执行 select * from userlog;
例题: 禁止在非工作时间(工作时间:星期一到星期五的9:00到18:00)往emp表插入数据
create or replace trigger tirg_insertWork after insert on empcopy for each row declare week varchar2(10); hours number; begin select to_char(sysdate, 'day'),to_char(sysdate, 'hh24') into week,hours from dual; if week in('星期六','星期天') or hours not between 9 and 18 then raise_application_error(-20001,'禁止在非工作时间插入数据'); else dbms_output.put_line('插入成功!!'); end if; end; -- 执行 declare begin insert into empcopy values('1234','james','CLERK','7902',sysdate,'2000',null,10); exception when others then dbms_output.put_line('插入失败,禁止在非工作时间插入数据!!'); end;