触发器
本节要点:
- 什么是触发器
- 触发器类型及创建方法
- 触发器类型
- 创建触发器
- 触发器组成部分
- 理解和应用触发器
- 行级触发器
- 语句级触发器
- INSTEAD OF 触发器
- 模式触发器
- 启用、禁用和删除触发器
1 什么是触发器
触发器和存储过程比较类似,它由PL/SQL编写并存储在数据库中,它可以调用存储过程,但是触发器本身的调用和存储过程调用是不一样的。存储过程由用户、应用程序、触发器或者其他过程调用。但是触发器只能由数据库的特定事件来触发。所以,触发器是当特定事件出现时自动执行的存储过程,不能被显式调用,特定事件可以是执行更新的DML语句和DDL语句。
触发器的作用:
- l 自动生成数据:如序列
- l 自定义复杂的安全权限:比如可以实现完整性规则
- l 提供审计和日志记录
- l 启用复杂的业务逻辑:除了基础数据变动还可以完成一些额外的操作
2 触发器类型及创建方法
触发器类型主要有DDL 触发器、数据库级触发器和DML触发器,其中DML触发器又可以分为语句级触发器、行级触发器和INSTEAD OF 触发器等。
2.1 触发器类型
- DDL 触发器:在模式中执行 DDL 语句时执行
- 数据库级触发器:在发生打开、关闭、登录和退出数据库等系统事件时执行
- DML 触发器:在对表或视图执行DML语句时执行
- 语句级触发器:无论受影响的行数是多少,都只执行一次
- 行级触发器:对DML语句修改的每个行执行一次
- INSTEAD OF 触发器:用于用户不能直接使用 DML 语句修改的视图
2.2 创建触发器
语法:
CREATE [OR REPLACE] TRIGGER trigger_name
AFTER | BEFORE | INSTEAD OF
[INSERT] [[OR] UPDATE [OF column_list]]
[[OR] DELETE]
ON table_or_view_name
[REFERENCING {OLD [AS] old / NEW [AS] new}]
[FOR EACH ROW]
[WHEN (condition)]
pl/sql_block;
- TRIGGER:触发器的关键词
- AFTER | BEFORE | INSTEAD OF:触发器类型为前触发|后触发|替换类型
- INSERT| UPDATE| DELETE:表示触发的事件
- [OF column_list]:触发条件具体到的某列
- ON table_or_view_name:触发器作用的表或视图
- [FOR EACH ROW]:表示行级触发,省略则为语句级触发器
- [WHEN (condition)]:触发该触发器的条件
- pl/sql_block:表示触发器的函数体
示例:为表m_user的user_pswd字段创建更新前触发的触发器,OLD.表示访问前的数据,:NEW.表示访问后的数据
CREATE OR REPLACE TRIGGER trig_stu
BEFORE UPDATE OF user_pswd ON m_user
FOR EACH ROW
WHEN (OLD.user_nm = '3')
BEGIN
:NEW.user_nm := '333333';
END;
更新语句
update m_user t set t.user_pswd='555' where t.user_cd='7';
2.3 触发器的组成部分
触发器由三部分组成:
1) 触发器语句(事件):定义激活触发器的 DML 事件和 DDL 事件
示例:为m_user表创建trig_stu触发器
CREATE OR REPLACE TRIGGER trig_stu
在更新 user_pswd列之前激活触发器
BEFORE UPDATE OF user_pswd ON m_user
2) 触发器限制:执行触发器的条件,该条件必须为真才能激活触发器,即WHEN (condition)部分
示例:只有在WHEN子句中的条件得到满足时,才激活trig_stu触发器
WHEN (OLD.user_nm = '3')
3) 触发器操作(主体):包含一些 SQL 语句和代码,它们在发出了触发器语句且触发限制的值为真时运行,即pl/sql_block部分
示例:如果WHEN子句中的条件得到满足,将执行BEGIN 块中的代码
:NEW.user_nm := '333333';
3 理解和应用触发器
3.1 行级触发器
创建表:
create table t_temp(f_id number,f_name varchar2(20));
创建序列:
create sequence seq_tempid;
创建触发器:
create trigger trig_temp
/*表t_temp更新或者插入字段f_id时触发器被触发*/
before insert or update of f_id on t_temp
for each row
begin
/*如果事件“inserting”发生,则执行1号语句,否则执行2号语句,注:不包括更新*/
if inserting then
select seq_tempid.nextval into :New.f_id from dual;/*1号*/
else
Raise_Application_Error(-20020, '不允许更新ID值!');/*2号*/
end if;
end;
插入数据(正常):
insert into t_temp (f_id,f_name) values('11','name1');
更新数据(报错):
update t_temp set f_id='11' where f_id='1';
删掉触发器:
drop trigger trig_temp;
再次更新数据(正常)。
说明:触发器的功能起作用。
3.2 语句级触发
create or replace trigger trig_stu
after insert or delete or update
on t_student
begin
if inserting then
dbms_output.put_line('已添加t_student中的数据');
elsif deleting then
dbms_output.put_line('已删除t_student中的数据');
elsif updating then
dbms_output.put_line('已更新t_student中的数据');
end if;
end;
注:没有for each row,根据语句的类型来触发相应的操作。
3.3 INSTEAD OF 触发器
在该类型的触发器作用下,如果对作用对象执行DML操作,那么该操作会被触发器的内部操作所取代。可以用在视图当中,解决视图不可更新的问题。
示例:对视图进行数据插入时,实际是操作其依附的真正存在的表productinfo,而productinfo表中产品类型信息是与表categroyinfo关联的,无法对视图直接进行数据插入。所以有了INSTEAD OF 触发器,在插入数据之前根据category查询出类型的编号categid,再进行数据插入。
- 表productinfo有七个字段:productid、productname、productprice、quantity、category、desperation、origin。
- 表categroyinfo保存了产品类型信息categroyid 和category
- 视图productinfo_view的定义
create view productinfo_view as
select distinct productname, productprice, quantity, category, origin
from productinfo
- 创建触发器
Create trigger instead_of_tgr
Instead of insert on productinfo_view
Declare
Categid varchar2(10);
Begin
Select categroyid
Into categid
From categroyinfo
Where categroyinfo.categroyname = :new.category;
Insert into productinfo
Values
(‘0240090001’,
:new. Productname,
:new. productprice,
:new. quantity,
Categid,
‘test’,
:new. Origin);
End;
- 对视图进行增加操作,最后productinfo中的category字段将对应categroyinfo中categroyid的编号。
Insert into productinfo_view values(‘触发器测试’,1000,0,’雨具’,’中国’);
3.4 模式触发器
也称DDL类型触发器,即因DDL操作而激发的触发器。利用模式触发器可以限制和记录特定的DDL操作。
示例:创建一个表和模式触发器,通过触发器将删除表的日志记录到表中
创建日志表:create table t_droppedobj
(
f_objname varchar2(20),
f_objtype varchar2(20),
f_dropdate date
);
创建触发器:create or replace trigger trig_dropobj
after drop on schema
begin
insert into t_droppedobj values
(Ora_Dict_Obj_Name,Ora_Dict_Obj_Type,Sysdate);
end;
3.5 启用、禁用和删除触发器
1) 启用触发器
ALTER TRIGGER trig_stu ENABLE;
2) 禁用触发器
ALTER TRIGGER trig_stu DISABLE;
3) 删除触发器
DROP TRIGGER trig_stu;
4) 查看有关触发器的信息:USER_TRIGGERS 数据字典视图包含有关触发器的信息
根据表名称查询触发器信息:
SELECT TRIGGER_NAME FROM USER_TRIGGERS
WHERE TABLE_NAME=‘M_USER '; /*注意表名称要大写*/
根据触发器名称查询触发器信息:
SELECT TRIGGER_TYPE, TRIGGERING_EVENT, WHEN_CLAUSE
FROM USER_TRIGGERS
WHERE TRIGGER_NAME = ‘TRIG_TEMP ';