15)触发器

Posted xuan01

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了15)触发器相关的知识,希望对你有一定的参考价值。

1、触发事件:

触发器定义了一系列操作,称为触发程序,当触发事件发生时,触发程序会自动运行;格式如下:

create trigger 触发器名 触发时间 触发事件 on 表名 for each row
begin
    触发程序
end;

触发时间:before、after;

触发事件:insert、update、delete;

for each now:表示行级触发器;

 

 2、使用触发器实现检查约束:

使用触发器实现检查约束,确保课程的人数上限 up_limit 字段值在(60,150,230)范围内;

delimiter $$
create trigger insert_before_course_trigger before insert on course for each row
begin
    if new.up_limit not in(60,150,230) then
     signal sqlstate \'ERROR\' set message_text = \'选修人数上限只能在60、150、230之间取值\'; #引发错误方式
    end if;
end;
$$
delimiter ;

new获取新值的标识符;old获取原值的标识符;使用格式:

new.字段 或 old.字段 

signal sqlstate 为引发错误的方式;

执行下列测试语句;

insert into course values(null,\'音乐鉴赏\',100,\'暂无\',default,\'005\');

 发现会报错;而且正是我们在signal那行所设定的 message_text 的值;原因在于我们设定的触发器就是让 up_limit 的值只能三选一;不能自定;

执行下列测试语句:

insert into course values(null,\'音乐鉴赏\',150,\'暂无\',default,\'005\');

 发现可以成功插入;

到此,我们执行update语句结果会怎么样呢?执行下列测试语句:我们更新course_no= 5 的up_limit的值:

update course set up_limit=100 where course_no = 5;

 发现成功update,这与我们设定的up_limit 的值不符合;那么我们如何修正呢?

那就是我们设定一个 update 的触发器;我们让其变更为原值;

delimiter $$
create trigger update_before_course_trigger before update on course for each row
begin
    if new.up_limit not in(60,150,230) then
     set new.up_limit = old.up_limit;
    end if;
end;
$$
delimiter ;

 那么我们将执行下列测试语句,修改为符合值;

update course set up_limit=150 where course_no = 5;

 可以发现我们可以修改为符合的值;再测试一下我们将其更新为不符合的值:

update course set up_limit=100 where course_no = 5;

 可以看到虽然我们匹配找到了一行,但是changed为0,就是未作update操作;

至此,我们的insert触发器和update触发器就完成了,维持 up_limit 的值只能在三选一;

我们可以再测试一下,当我们同时修改其他字段时:

update course set up_limit=100, status=\'已审核\' where course_no = 5;

 可以发现,我们的up_limit 字段未作修改,但是status更新为已审核了,因为我们没有对该字段进行约束,符合预期;

 

3、查看和删除触发器:

#查看所有触发器
show triggers\\G

#查看指定触发器名
show create trigger 触发器名\\G
show create trigger insert_before_course_trigger\\G

 貌似MySQL8.0版本之后不支持下列模糊查看了:

show trigger like \'%trigger\'\\G

通过查询GPT,可以使用以下方法:

select * from information_schema.triggers where trigger_name like \'%\\_trigger\'\\G

查询information_schema下的triggers表,通过匹配名字进行模糊查找;

 

删除触发器命令:

#删除触发器
drop trigger 触发器;

 

触发器

本节要点:

  • 什么是触发器
  • 触发器类型及创建方法
    •   触发器类型
    •   创建触发器
    •   触发器组成部分
  • 理解和应用触发器
    •   行级触发器
    •   语句级触发器
    •   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 ‘; 

以上是关于15)触发器的主要内容,如果未能解决你的问题,请参考以下文章

mysql_15_触发器

核心数据,仅获取 15 行,然后在事件触发时获取下 15 行

MySQL(15)-触发器

MySQL(15)-触发器

定时器触发 Tick 事件,延迟 15 毫秒

至少每 15 分钟不会触发重大位置变化