首页 理论教育 MySQL数据库应用与实例教程:触发器的创建及应用

MySQL数据库应用与实例教程:触发器的创建及应用

时间:2023-11-22 理论教育 版权反馈
【摘要】:BEFORE表示在触发事件发生之前执行触发程序。同一个表不能拥有两个具有相同触发时刻和事件的触发器。创建user和user_history表,以及三个触发器tri_insert_user、tri_update_user、tri_delete_user,分别对应user表的增、删、改三个事件。图8.2 插入触发器的创建创建user表更新事件对应的触发器tri_update_user。

MySQL数据库应用与实例教程:触发器的创建及应用

简单地说,触发器就是一张表发生了某件事(插入、删除、更新操作)后,自动触发了预先编写好的若干条SQL语句的执行。触发器是一种特殊的事务,它监听增删改操作,并触发增删改操作。主要是用来处理一些比较复杂的业务逻辑以保证数据的联动性。其包含四个要素:监视地点(table);监视事件(insert/update/delete);触发时间(after/before);触发事件(insert/update/delete)。

触发器的特点是触发事件的操作和触发器里的SQL语句是一个事务操作,具有原子性,要么全部执行,要么都不执行。其作用是保证数据的完整性,起到约束的作用。

触发器主要用于监视某个表的insert、update以及delete等更新操作,这些操作可以分别激活该表的insert、update或者delete类型的触发程序运行,从而实现数据的自动维护,如图8.1所示。

图8.1 触发器原理图

8.1.1 触发器的创建与测试

创建触发器的语法格式如下:

CREATE TRIGGER 触发器名 触发时间 触发事件 ON 表名 FOR EACH ROW

BEGIN

触发程序

END

MySQL的触发事件有三种:

➢ INSERT:将新记录插入表时激活触发程序,例如通过insert、load data和replace语句,可以激活触发程序运行。

➢ UPDATE:更改某一行记录时激活触发程序,例如通过update语句,可以激活触发程序运行。

➢ DELETE:从表中删除某一行记录时激活触发程序,例如通过delete和replace语句,可以激活触发程序运行。

触发器的触发时间有两种:BEFORE与AFTER,以表示触发器是在激活它的语句之前还是之后触发。

➢ BEFORE表示在触发事件发生之前执行触发程序。

➢ AFTER表示在触发事件发生之后执行触发程序。

因此,严格意义上讲,一个数据库表最多可以设置六种类型的触发器。

“触发地点”(表名):与触发器相关的表名,在该表上发生触发事件才会激活触发器。同一个表不能拥有两个具有相同触发时刻和事件的触发器。

触发器动作:包含触发器激活时将要执行的语句。如果要执行多个语句,可使用BEGIN ...END复合语句结构。

➢ FOR EACH ROW表示行级触发器:FOR EACH ROW 用来标识触发器的类型,目前MySQL仅支持行级触发器,不支持语句级别的触发器(例如CREATE TABLE等语句)。FOR EACH ROW表示更新(INSERT、UPDATE或者DELETE)操作影响的每一条记录都会执行一次触发程序。

触发程序中可以使用OLD关键字与NEW关键字。

对于INSERT语句,只有NEW是合法的;对于DELETE语句,只有OLD是合法的;而UPDATE语句可以与NEW或OLD同时使用。

·当向表插入新记录时,在触发程序中可以使用new关键字表示新记录,当需要访问新记录的某个字段值时,可以使用“NEW.字段名”的方式访问。

·当从表中删除某条旧记录时,在触发程序中可以使用OLD关键字表示旧记录,当需要访问旧记录的某个字段值时,可以使用“OLD.字段名”的方式访问。

·当修改表的某条记录时,在触发程序中可以使用OLD关键字表示修改前的旧记录、使用NEW关键字表示修改后的新记录。当需要访问旧记录的某个字段值时,可以使用“OLD.字段名”的方式访问。当需要访问修改后的新记录的某个字段值时,可以使用“NEW.字段名”的方式访问。

· OLD记录是只读的,可以引用它,但不能更改它。在BEFORE触发程序中,可使用“SET NEW.COL_NAME = VALUE”更改NEW记录的值。

【例8.1】创建user和user_history表,以及三个触发器tri_insert_user、tri_update_user、tri_delete_user,分别对应user表的增、删、改三个事件。

(1)创建user表。

CREATE TABLE user (

id bigint(20)NOT NULL AUTO_INCREMENT,

account varchar(255)DEFAULT NULL,

name varchar(255)DEFAULT NULL,

address varchar(255)DEFAULT NULL,

PRIMARY KEY(id)

)ENGINE=InnoDB DEFAULT CHARSET=utf8;

(2)创建对user表操作历史表user_history。

CREATE TABLE user_history(

id bigint(20)NOT NULL AUTO_INCREMENT,

user_id bigint(20)NOT NULL,

operatetype varchar(200)NOT NULL,

operatetime datetime NOT NULL,

PRIMARY KEY(id)

)ENGINE=InnoDB DEFAULT CHARSET=utf8;

(3)创建user表插入事件对应的触发器tri_insert_user,当向表user中添加一条记录时,user_history表被触发,自动产生new.id,增加新用户,记录插入用户的当前时间。

CREATE TRIGGER tri_insert_user AFTER INSERT ON user FOR EACH ROW begin

INSERT INTO user_history(user_id,operatetype,operatetime)VALUES(new.id,'add a user',now());

End

执行结果如图8.2所示。

图8.2 插入触发器的创建

(4)创建user表更新事件对应的触发器tri_update_user。

CREATE TRIGGER tri_update_user AFTER UPDATE ON user FOR EACH ROW begin

INSERT INTO user_history(user_id,operatetype,operatetime)VALUES(new.id,'update a user',now());

End

执行结果如图8.3所示。

图8.3 更新触发器的创建

(5)创建user表删除事件对应的触发器tri_delete_user。

CREATE TRIGGER tri_delete_user AFTER DELETE

ON user FOR EACH ROW

begin

INSERT INTO user_history(user_id,operatetype,operatetime)VALUES(old.id,'delete a user',now());

End

执行结果如图8.4所示。

图8.4 删除触发器的创建

(6)至此,全部表及触发器创建完成,开始验证结果。分别做插入、修改、删除事件,执行以下语句,观察user_history是否自动产生操作记录。

INSERT INTO user(account,name,address)VALUES('user1','user1','user1');

INSERT INTO user(account,name,address)VALUES('user2','user2','user2');

执行结果如图8.5所示。

图8.5 向user表中插入记录

select * from user_history;

执行结果如图8.6所示。

图8.6 插入触发器生效后对表user_history产生影响后的记录

UPDATE user SET name = 'user3',account = 'user3',address='user3' where name='user1';

执行结果如图8.7所示。

图8.7 更新user表中的数据

select * from user_history;

执行结果如图8.8所示。

图8.8 更新触发器生效后对表user_history产生影响后的记录

DELETE FROM user where name = 'user2';

执行结果如图8.9所示。

图8.9 删除user表中的数据

select * from user_history;

执行结果如图8.10所示。

图8.10 删除触发器生效后对表user_history产生影响后的记录

【例8.2】触发器示例。

(1)创建用户表uuser。

CREATE TABLE uuser(

Id int(11)NOT NULL auto_increment COMMENT '用户ID',

name varchar(50)NOT NULL default '' COMMENT '名称',

sex int(1)NOT NULL default '0' COMMENT '0为男,1为女',

PRIMARY KEY(id)

)ENGINE=MyISAM DEFAULT CHARSET=utf8;

执行结果如图8.11所示。

(www.xing528.com)

图8.11 创建表uuser

INSERT INTO uuser( name,sex)VALUES

('张映',0),

('tank',0);

执行结果如图8.12、8.13所示。

图8.12 向表uuser插入记录

图8.13 uuser表中记录

(2)创建评论表comment。

CREATE TABLE comment(

c_id int(11)NOT NULL auto_increment COMMENT '评论ID',

u_id int(11)NOT NULL COMMENT '用户ID',

name varchar(50)NOT NULL default '' COMMENT '用户名称',

content varchar(1000)NOT NULL default '' COMMENT '评论内容',

PRIMARY KEY (c_id)

)ENGINE=MyISAM DEFAULT CHARSET=utf8;

执行结果如图8.14所示。

图8.14 创建表comment

INSERT INTO comment(c_id,u_id,name,content)VALUES

(1,1,'张映','触发器测试'),

(2,1,'张映','解决字段冗余'),

(3,2,'tank','使代码更简单');

执行结果如图8.15、8.16所示。

图8.15 向表comment插入记录

图8.16 comment表中记录

(3)更新name触发器。

create trigger updatename after update on uuser for each row //建立触发器,

begin

//old,new都是代表当前操作的记录行,将其当成表名也行;

if new.name!=old.name then //当表中用户名称发生变化时,执行

update comment set comment.name=new.name where comment.u_id=old.id;

end if;

end

执行结果如图8.17所示。

图8.17 创建更新触发器

(4)触发器删除comment数据。

create trigger deletecomment before delete on uuser for each row

begin

delete from comment where comment.u_id=old.id;

end

执行结果如图8.18所示。

图8.18 创建删除触发器

(5)测试update触发器。

update uuser set name='苍鹰' where id = 1;

执行结果如图8.19所示。图8.20显示了comment表在更新触发器生效前后记录的变化。

图8.19 更新操作

图8.20 更新触发器生效前后记录对比

(6)测试delete触发器。

delete from uuser where id = 1;

执行结果如图8.21所示。图8.22显示了comment表在删除触发器生效前后记录的变化。

图8.21 删除操作

图8.22 删除触发器生效前后记录对比

8.1.2 查看触发器

可以使用下面4种方法查看触发器信息。

(1)可以使用SHOW TRIGGERS语句查看触发器信息。

SHOW TRIGGERS;

(2)在INFORMATION_SCHEMA数据库中的TRIGGERS表中查询触发器信息。

SELECT TRIGGER_NAME,EVENT_MANIPULATION FROM information_schema.TRIGGERS WHERE TRIGGER_NAME like 'tri_%_user'

执行结果如图8.23所示。

图8.23 在TRIGGERS 表中查看已有触发器

(3)使用“show create trigger”命令可以查看某一个触发器的信息。

例如,使用“show create trigger organization_delete_before_trigger\G”命令可以查看触发器organization_delete_before_trigger的信息。

(4)成功创建触发器后,MySQL自动在数据库目录下创建TRN以及TRG触发器文件,以记事本方式打开这些文件,可以查看触发器的信息。

8.1.3 删除触发器

使用DROP TRIGGER语句可以删除MySQL中已经定义的触发器,删除触发器的基本语法格式下:

DROP TRIGGER [schema_name.]trigger_name

【例8.3】创建一个触发器,当删除表XSB中某个学生的信息时,同时将CJB表中与该学生有关的数据全部删除。

现在验证一下触发器的功能:

DELETE FROM XSB WHERE 学号='081101';

使用SELECT语句查看CJB表中的情况:

SELECT * FROM CJB;

删除触发器也是使用DROP语句,例如:

DROP TRIGGER XS_DELETE;

8.1.4 使用触发器实现检查约束

前面曾经提到,MySQL可以使用复合数据类型set或者enum对字段的取值范围进行检查约束,使用复合数据类型可以实现离散的字符串数据的检查约束,对于数值型的数不建议使用set或者enum实现检查约束,可以使用触发器实现。

1.使用触发器维护冗余数据

冗余的数据需要额外的维护,维护冗余数据时,为了避免数据不一致问题的发生(例如:剩余的学生名额+已选学生人数≠课程的人数上限),冗余的数据应该尽量避免交由人工维护,建议冗余的数据交由应用系统(例如触发器)自动维护。

2.使用触发器模拟外键级联选项

对于InnoDB存储引擎的表而言,由于支持外键约束,在定义外键约束时,通过设置外键的级联选项cascade、set null或者no action(restrict),外键约束关系可以交由InnoDB存储引擎自动维护。

8.1.5 使用触发器的10条注意事项

(1)触发程序中如果包含select语句,该select语句不能返回结果集。

(2)同一个表不能创建两个相同触发时间、触发事件的触发程序。

(3)触发程序中不能使用以显式或隐式方式打开、开始或结束事务的语句,如start transaction、commit、rollback或者set autocommit=0等语句。

(4)MySQL触发器针对记录进行操作,当批量更新数据时,引入触发器会导致更新操作性能降低。

(5)在MyISAM存储引擎中,触发器不能保证原子性。InnoDB存储引擎支持事务,使用触发器可以保证更新操作与触发程序的原子性,此时触发程序和更新操作是在同一个事务中完成。

(6)InnoDB存储引擎实现外键约束关系时,建议使用级联选项维护外键数据;MyISAM存储引擎虽然不支持外键约束关系,但可以使用触发器实现级联修改和级联删除,进而维护“外键”数据,模拟实现外键约束关系。

(7)使用触发器维护InnoDB外键约束的级联选项时,数据库开发人员究竟应该选择after触发器还是before触发器?答案是应该首先维护子表的数据,然后再维护父表的数据,否则可能会出现错误

(8)MySQL的触发程序不能对本表进行更新语句(例如update语句)。触发程序中的更新操作可以直接使用set命令替代,否则可能会出现错误信息,甚至陷入死循环。

(9)在before触发程序中,auto_increment字段的new值为0,不是实际插入新记录时自动生成的自增型字段值。

(10)添加触发器后,建议对其进行详细的测试,测试通过后再决定是否使用该触发器。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈