mysql触发器详解

1.1 触发器是什么

  • 触发器(trigger)是个特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作( insert,delete, update)时就会激活它执行。

1.2 触发器的特性与作用

  • 触发器经常用于加强数据的完整性约束和业务规则等。有一个非常好的特性就是触发器可以禁止或回滚违反引用完整性的更改,从而取消所尝试的数据修改。
  • 触发程序视为单一交易中的一部份,因此可以由原触发程序还原交易,如果在交易过程中侦测到严重的错误(如使用者中断连线),则会自动还原整个交易。他的作用很明显了,可以保重数据的完整性。
  • 触发器虽然能解决好多问题,但是在高并发场景下,最好不要用触发器,触发器会影响数据库的性能,可以在代码中实现相关逻辑。还有,触发器会带来维护上的一些问题。

1.3 触发器的语法

CREATE TRIGGER trigger_name BEFORE | AFTER  trigger_event
    ON tbl_name FOR EACH ROW trigger_stmt

语法详细说明:
- trigger_name。触发程序与命名为tbl_name的表相关。tbl_name必须引用永久性表。不能将触发程序与TEMPORARY表或视图关联起来。
- BEFORE | AFTER。是触发程序的动作时间。它可以是BEFORE或AFTER,以指明触发程序是在激活它的语句之前或之后触发。
- trigger_event。指明了激活触发程序的语句的类型。trigger_event可以是下述值之一:
· INSERT:将新行插入表时激活触发程序,例如,通过INSERT、LOAD DATA和REPLACE语句。
· UPDATE:更改某一行时激活触发程序,例如,通过UPDATE语句。
· DELETE:从表中删除某一行时激活触发程序,例如,通过DELETE和REPLACE语句。
- trigger_stmt。是当触发程序激活时执行的语句。如果你打算执行多个语句,可使用BEGIN … END复合语句结构。这样,就能使用存储子程序中允许的相同语句

需要注意的几个地方:
- 注意点一,trigger_event与以表操作方式激活触发程序的SQL语句并不很类似,这点很重要。例如,关于INSERT的BEFORE触发程序不仅能被INSERT语句激活,也能被LOAD DATA语句激活。
- 注意点二,可能会造成混淆的例子之一是INSERT INTO .. ON DUPLICATE UPDATE …语法:BEFORE INSERT触发程序对于每一行将激活,后跟AFTER INSERT触发程序,或BEFORE UPDATE和AFTER UPDATE触发程序,具体情况取决于行上是否有重复键。
- 注意点三,对于具有相同触发程序动作时间和事件的给定表,不能有两个触发程序。例如,对于某一表,不能有两个BEFORE UPDATE触发程序。但可以有1个BEFORE UPDATE触发程序和1个BEFORE INSERT触发程序,或1个BEFORE UPDATE触发程序和1个AFTER UPDATE触发程序。
- 注意点四,插入时出现错误:

[Err] 1442 - Can't update table 'comment' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.

导致此错误的原因是在一张表中的触发器,不能直接对同一张表执行 增加,删除,修改操作,防止造成死循环。应该在FOR EACH ROW 中使用set操作,而不是在触发器里使用 update。

1.4 例子

需要提前说明的问题:
- 在下面的sql中,出现的new和old需要注意的问题,对于INSERT语句,只有new是合法的;对于DELETE语句,只有old才合法;而UPDATE语句可以在和new以及old同时使用。
- 在Oracle中用 :old 和 :new 表示执行前的行,和执行后的行。在MySQL中用old和new表示执行前和执行后的数据。
1.测试所用的表

## 用户表user
CREATE TABLE `user` (  
`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 ;  

INSERT INTO `user` (`id`, `name`, `sex`) VALUES  
(1, '张映', 0),  
(2, 'tank', 0);  

## 评论表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 ;  

INSERT INTO `comment` (`c_id`, `u_id`, `name`, `content`) VALUES  
(1, 1, '张映', '触发器测试'),  
(2, 1, '张映', '解决字段冗余'),  
(3, 2, 'tank', '使代码更简单');

2.触发器测试

## 当我更新user表的name时,触发器同时更
## 新comment表,就不要写代码去更新了,
## 当用户被删除时,comment表中,有关该
## 用户的数据将被删除。

delimiter $$

## 更新name触发器
CREATE TRIGGER trigger_name 
AFTER UPDATE ON `user` 
FOR EACH ROW 
    BEGIN
        /*old是更新前的表,new是更新后的表*/
        IF old.name != new.name THEN
            UPDATE `comment` 
            SET `comment`.name = new.name 
            WHERE `comment`.u_id = old.id; 
        END IF;
    END $$

## 删除对应记录触发器
CREATE TRIGGER delete_trigger 
BEFORE DELETE ON `user`
FOR EACH ROW
    BEGIN
        DELETE FROM `comment` 
        WHERE `comment`.u_id = old.id;
    END $$

delimiter ;

UPDATE `user` SET name = '触发器更新' 
WHERE id = 1;

DELETE FROM `user` 
WHERE id = 1;

猜你喜欢

转载自blog.csdn.net/jiang13479/article/details/54584627