PL/SQL之--触发器
一、简介
触发器在数据库里以独立的对象进行存储,它与存储过程和函数不同的是,存储过程与函数需要用户显示调用才执行,而触发器是由一个事件来触发运行。oracle事件指的是对数据库的表或视图进行的insert、update及delete操作或对视图进行类似的操作。oracle将触发器的功能扩展到了触发ORACLE,如用户的登录、数据库的启动与关闭等。所以触发器常用来完成由数据库的完整性约束难以完成的复杂业务规则的约束,或用来监视对数据库的各种操作,实现审计相关的功能。
触发器的组成如下:
触发事件:在任何情况下触发trigger;如insert,update,delete
触发时间:该trigger是在触发事件发生之前(before)还是之后(after)触发,也就是触发事件和该trigger的操作顺序。
触发器本身:该trigger被触发之后的执行体。例如PL/SQL块。
触发频率:说明触发器内定义的动作被执行的次数。即语句级(statement)触发器和行级(row)触发器
语句级(statement)触发器:指当触发事件发生时,该触发器只执行一次;
行级(row)触发器:指当某触发事件发生时,对收到该操作一下的每一行数据,触发器都单独执行。
oracle触发器分为如下三种:
1、DML触发器 DML 数据操纵语言(Data Manipulation Language)
在DML语句(insert、update及delete)进行触发,可以在DML操作前或操作后进行触发,并且可以对每个行或语句操作上进行触发。
2、替代触发器
由于在ORACLE里,不能直接对由两个以上的表建立的视图进行操作。所以给出了替代触发器。它就是ORACLE 8专门为进行视图操作的一种处理方法。
3、系统触发器
ORACLE 8i 提供了第三种类型的触发器叫系统触发器。它可以在ORACLE数据库系统的事件中进行触发,如ORACLE系统的启动与关闭等。
二、DML触发器
oracle可以在dml语句进行触发,可以在dml操作前或操作后进行触发,并且可以对每个行(行级)或语句(级)操作上进行触发。DML触发器分为如下两种触发器:
- 行触发器:是指为受到影响的各个行激活的触发器,定义与语句触发器类似,有以下两个例外:
1、定义语句中包含FOR EACH ROW子句。
2、在BEFORE……FOR EACH ROW触发器中,用户可以引用受到影响的行值。
- 语句触发器:是在表上或者某些情况下的视图上执行的特定语句或者语句组上的触发器。能够与INSERT、UPDATE、DELETE或 者组合上进行关联。但是无论使用什么样的组合,各个语句触发器都只会针对指定语句激活一次。无论update多少行,也只会调用一次update语句触发器。
创建触发器的一般语法如下:
create or replace trigger trigger_name
{before|after}
{insert|delete|update[of column]}
on [schema] table_name
[referencing {old[as] old|new[as]new|parent as parent}]
[for each row]
[when condition]
trigger body;
以下person表结构如下:
DROP TABLE person ;
CREATE TABLE person (
id NUMBER(11) NOT NULL ,
username VARCHAR2(255 ) NULL ,
age NUMBER(11) NULL ,
password VARCHAR2(255) NULL ,
PRIMARY KEY (id)
)
1、insert行级触发器
create or replace trigger trigger_insert
before insert on person
referencing new as new old as old
for each row
declare
v_username varchar2(50);
begin
v_username := :new.username;
:new.age := :new.age + 2; --插入的年龄加2
dbms_output.put_line(v_username); -- 插入插入记录的username字段
end trigger_insert;
--添加数据
insert into person values (1, '张三', 20, 'zhangsan');
2、update行级触发器
create or replace trigger trigger_update_before
before update on person
referencing new as new old as old
for each row
declare
v_username varchar2(50);
begin
v_username := :new.username; -- 记录新名字
:new.age := :new.age + 3; -- 修改年龄
dbms_output.put_line(v_username);
end trigger_update_before;
-- after update 触发器
create or replace trigger trigger_update_after
before update on person
referencing new as new old as old
for each row
declare
v_old_name varchar2(50);
begin
v_old_name := :old.username; -- 记录修改前的名字
dbms_output.put_line(v_old_name);
end trigger_update_after;
-- 更新数据
update person set username='张三1', age = 19 where id = 1;
3、delete行级触发器
create or replace trigger trigger_delete
before delete on person
referencing new as new old as old
for each row
declare
v_old_name varchar2(50);
begin
v_old_name := :old.username; -- 获取被删除的用户名称
dbms_output.put_line(v_old_name);
end trigger_delete;
--删除数据
delete from person where id = 1;
4、语句触发器
-- 记录操作表的信息
create table person_log(
who varchar2(30),
when date,
action varchar2(50)
)
--触发器
create or replace trigger trigger_person_statment
before insert or update or delete on person
declare
-- 保存操作信息
v_action person_log.action%type;
begin
if inserting then
v_action := 'Insert';
elsif updating then
v_action := 'Update';
elsif deleting then
v_action := 'Delete';
else
raise_application_error(-20001,'You should never ever get this error.');
end if;
insert into person_log(who,action,when)
values(user, v_action,sysdate);
end trigger_person_statment;
-- 操作shuj
declare
begin
insert into person values(1003, '', 20, '');
insert into person values(1004, '', 20, '');
update person set age = 19 where id >1000 and id <1003;-- 此时触发器之后执行一次
delete from person where id >1000 and id <1003;-- 此时触发器之后执行一次
end;
触发器触发次序
1、执行BEFORE语句级触发器;
2、对与受语句影响的每一行
2.1、执行BEFORE行级触发器
2.2、执行DML语句
2.3、执行AFTER行级触发器
3、执行AFTER语句级触发器
三、替代触发器
用于执行一个替代操作来代替触发事件的操作。例如:针对INSERT事件的替代触发器,它由INSERT语句触发,当出现INSERT语句时,该语句不会被执行,而是执行替代触发器中定义的语句。
创建INSTEADOF触发器需要注意以下几点:
- 只能被创建在视图上,并且该视图没有指定WITHCHECKOPTION选项。
- 不能指定BEFORE或AFTER选项。FOREACHROW子可是可选的,即INSTEADOF触发器只能在行级上触发、或只能是行级触发器,没有必要指定。
- 没有必要在针对一个表的视图上创建INSTEADOF触发器,只要创建DML触发器就可以了.
示例代码:
-- 视图
create or replace view v_person as
select username, age, password, id p_id from person;
-- 触发器
create or replace trigger update_v_person INSTEAD OF
update on v_person
begin
update person set
username = substr(:new.username, instr(:new.username,',')+2),
age = :new.age,
password = :new.password
where id = :new.p_id; -- 视图中p_id字段
end update_v_person; -- 尝试更新name
update person set username = 'Chen1, Donny1', age =18 where id=1
select * from person where id = 1;
四、系统触发器
系统事件触发器在发生如数据库启动或者关闭等系统事件时触发,包括数据库服务器的启动或关闭,用户的登录与退出、数据库服务错误等。系统触发器可以在DDL语句(数据库定义语句,如crate,alter,drop等)事件来触发。
系统触发器的时间和运行时机如下:
事件 | 运行启动的时机 | 说明 |
启动(startup) | 之后 | 实例启动时激活 |
关闭(shutdown) | 之前 | 实例正常关闭时激活 |
服务器错误(servererror) | 之后 | 只要有错误就激活 |
登录(login) | 之后 | 成功登录后激活 |
注销(logoff) | 之前 | 开始注销时激活 |
创建(create) | 之前,之后 | 在创建之前或之后激活 |
删除(delete) | 之前,之后 | 在撤销之前或之后激活 |
修改(alter) | 之前,之后 | 在变更之前或之后激活 |
示例
记录用户登录信息
-- 准备表登录后保存用户登录信息
create table loggin_event(
username varchar2(50),
logintime date
);
-- 登录触发器
create or replace trigger t_login
after LOGON ON DATABASE
declare begin
-- 保存用户登录信息
insert into loggin_event(username, logintime)
values (USER, sysdate);
commit;
end t_login;
记录创建表的信息
-- 记录创建表的信息
drop table test_create_log;
create table test_create_log(
event varchar2(50),
type varchar2(50),
name varchar2(50),
owner varchar2(50),
createtime date default sysdate
); -- 创建表的时候记录
create or replace trigger t_create
after create on database
declare
v_event varchar2(50);
v_type varchar2(50);
v_name varchar2(50);
v_owner varchar2(50);
begin
-- 读取DDL事件属性
v_event := sysevent; --事件
v_type := dictionary_obj_type; -- 对象类型,如表
v_name := dictionary_obj_name; -- 对象名称;如表没
v_owner := dictionary_obj_owner; -- 拥有者
insert into test_create_log values(v_event, v_type, v_name, v_owner, sysdate);
end t_create; select * from test_create_log;
drop table t_1;
create table t_1(id number);
select * from test_create_log;
四、触发器需要注意的地方
before和afterz是支持触发器的触发时间,是前触发还是后触发。
for each row 说名触发器是行触发器。当圣灵for each row语句时,触发器为语句触发器,替代触发器(instead of )为行触发器。
feferencing 子句说明相关名称,在行触发器的PL/SQL块和WHEN子句中可以使用相关名称,参照当前的新、旧列值,默认的名称成为old和new。触发器的PL/SQL块中应相关名称时,必须在他们之前加冒号(:),但在when子句中则不能加冒号。
:new 访问操作完成后的值,:old访问操作完成前的值。
对于insert 只有:new有效,对于update :new、:old都有效,对于delete只有:old有效。
oracle触发器的应用一般应用在以下方面:
1、数据库的安全性
可以基于时间限制用户的操作,例如不允许下班后和节假日修改数据库数据。可以基于数据库中的数据限制用户的操作,例如不允许价格的升幅一次超过10%。
2、实施复杂的安全性授权
利用触发器控制实体的安全性,可以将权限藉于各种数据库的值。
3、提供复杂的审计功能
审计用户操作数据库的语句。把用户对数据库的更新写入审计表。
4、维护不同数据库之间同步表
在不同的数据库之间可以利用快照来实现数据的复制,但有些系统(例如某个系统有两个数据库,一个只提供系统读,一个值提供系统写)要求两个数据库数据
实时同步,就必须利用触发器从一个数据库中向另一个数据库复制数据。
5、实现复杂的数据完整性规则
实现非标准的数据完整性检查和约束。触发器可产生比规则更为复杂的限制。与规则不
同,触发器可以引用列或数据库对象。提供可变的缺省值。
6、实现复杂的非标准的数据库相关完整性规则
触发器可以对数据库中相关的表进行连环更新。例如,在auths表author_code列上的
删除触发器可导致相应删除在其它表中的与之匹配的行。触发器能够拒绝或回退那些破坏相关完整性的变化,取消试图进行数据更新的事务。当插入一个与其主健不匹配的外部键时,这种触发器会起作用。
7、可提供表的同步复制
8、事件日志记录
PL/SQL之--触发器的更多相关文章
- Oracle数据库编程:使用PL/SQL编写触发器
8.使用PL/SQL编写触发器: 触发器存放在数据缓冲区中. 触发器加序列能够实现自动增长. 在触发器中不能使用connit和rollback. DML触发器 ...
- ORACLE PL/SQL:触发器
ORACLE PL/SQL 触发器 本篇主要内容如下: 8.1 触发器类型 8.1.1 DML触发器 8.1.2 替代触发器 8.1.3 系统触发器 8.2 创建触发器 8.2.1 触发器触发次序 8 ...
- 开发PL/SQL子程序和包及使用PL/SQL编写触发器、在JDBC中应用Oracle
1. 子程序的各个部分: 声明部分.可执行部分.异常处理部分(可选) 2.子程序的分类: A. 过程 - 执行某些操作 a. 创建过程的语法: CREATE [OR REPLACE] PROC ...
- 【PL/SQL】触发器示例:记录加薪
首先创建一张表,用于保存薪资变化情况: --创建加薪记录表 CREATE TABLE scott.raisedsalarylog ( empno ) NOT NULL PRIMARY KEY, --员 ...
- PL/SQL 07 触发器 trigger
--触发器 触发器有三类: 数据操作触发器 用before触发器进行数据校验 用after触发器进行级联操作 语句触发器限制数据的操作和记录操作日志 instead of 触发 ...
- PL/SQL详细介绍,设置oracle相关
1. 实现参照完整性 指若两个表之间具有主从关系(即主外键关系),当删除主表数据时,必须确保相关的从表数据已经被删除. 当修改主表的主键列数据时,必须确保相关从表数据已经被修改.为了实现级 ...
- PL/SQL -->隐式游标(SQL%FOUND)
PL/SQL -->隐式游标(SQL%FOUND) 分类: SQL/PLSQL 基础2010-12-22 16:23 4084人阅读 评论(0) 收藏 举报 sqlexceptionoracle ...
- 【Java EE 学习 29 上】【PL/SQL】【存储过程】【存储函数】【触发器】
一.PL/SQL简介 1.概念:PL/SQL语言是Oracle数据库专用的一种高级程序设计语言,是对标准SQL语言进行了过程化扩展的语言. 2.功能:既能够实现对数据库的操作,也能够通过过程化语言中的 ...
- oracle PL/SQL(procedure language/SQL)程序设计之触发器(trigger)
创建触发器 触发器类似于过程和函数,都拥有声明.执行和异常处理过程的带名PL/SQL块.与包类似,触发器必须存储在数据库中.前面已经讲过,过程是显式地通过过程调用执行的,同时过程调用可以传递参数.与之 ...
随机推荐
- CMD魔法堂:支持显示UTF8编码的中文
一.前言 在Unbuntu中用sqlite3-command-line操作sqlite3还好好的,到了windows下查询表内容时发现中文全部乱码了!马上想到sqlite3内部使用utf-8对字符进行 ...
- 连续值的CART(分类回归树)原理和实现
上一篇我们学习和实现了CART(分类回归树),不过主要是针对离散值的分类实现,下面我们来看下连续值的cart分类树如何实现 思考连续值和离散值的不同之处: 二分子树的时候不同:离散值需要求出最优的两个 ...
- jQuery实现表格拖动排序
原理就是利用mousedown.mouseover.mouseup事件实现拖动,并用Ajax实现保存结果. JS代码如下: <!--题目调序功能--> <script type=&q ...
- C语言中有bool类型吗?
之前一直都没有注意到,最近在用C语言写DSP算法时,偶然间发现我函数中定义的bool类型的变量在VC6.0(我主要用它来检查一下语法错误)中编译居然报错了,说是bool类型没有定义.用了这么久的C和C ...
- 【Android】将Xamarin For VS升级为4.1.0.530版
分类:C#.Android.VS2015(自带Update2).Win10 创建日期:2016-06-10 2016-08-03说明:该版本已过时,新版本详见本博客置顶的更新. 一.Xamarin f ...
- 轻松解决MYSQL数据库连接过多的错误
1.数据库系统允许的最大可连接数max_connections.这个参数是可以设置的.如果不设置,默认是100.最大是16384. 2.数据库当前的连接线程数threads_connected.这是动 ...
- jython 2.7 b3发布
Jython 2.7b3 Bugs Fixed - [ 2108 ] Cannot set attribute to instances of AST/PythonTree (blocks pyfla ...
- java之内的工具分享,附带下载链接,方便以后自己寻找
class反编译工具:http://pan.baidu.com/s/1geYvX5L redis客户端工具:http://pan.baidu.com/s/1eRJ4ThC mysql客户端-[mysq ...
- 【NOIP训练】【规律+数论】欧拉函数的应用
Problem 1 [题目大意] 给出 多组数据 ,给出 求出 . 题解 证明: 除了 以为均为偶数, 所以互质的个数成对. 由 得 . 所以对于每对的和为 , 共有 对 . 则 Problem ...
- [Tool] 使用CodeMaid自动程序排版
[Tool] 使用CodeMaid自动程序排版 前言 「使用StyleCop验证命名规则」这篇文章,指引开发人员透过StyleCop这个工具,来自动检验项目中产出的程序代码是否合乎命名规则. [Too ...