当前位置:首页>资讯中心>技术文章>MySQL触发器事件讲解

MySQL触发器事件讲解

发布时间:2017-06-02 点击数:3428

本这逍遥子科技主要为各位介绍的是触发器(Trigger)。在介绍 Trigger 的语法前,先和读者聊聊触发器的特性。

MySQL 正式支持触发器是在 MySQL 5.0.2 的版本之后。触发器是注册在数据库表格上的程序。所以,在事件发生(对数据列做新增/修改/删除)时,数据库会依照触发条件(事件前/事件后)帮你执行预先储存好的程序。因此,常常有人利用触发器来验证数据的正确性,或做数据计算。

也因为触发器的功能十分强大,所以偶而就会发现有些人喜欢在将商业逻辑加到触发器中,甚至加了大量的触发器在单一的数据表中。但是触发器是非常昂贵的解决方案,就像是金庸笔下的七伤拳(先伤己,再伤敌;伤敌七分,自损三分),它会耗用大量的系统资源(尤其当在数据量非常庞大的系统中),过度的使用,反而造成数据库的效能下降,不可不防。

另外一个重点是,在支持交易(transaction)的储存引擎中,一但表格有设定触发器,则整个交易行为(包含触发器的新增/修改/删除等全部的操作),也是不可分割的(atomic)。

接下来,我们来介绍出发器的时机,事件与对象的种类与关系。

触发器的时机:

事件前:
before
事件后:
after

触发器事件:

新增:
insert
load data
replace
修改:
update
删除:
update
replace
不包括(drop table, truncate table)

参考对象:

NEW:表示”新”的数据对象。在下列的操作时会出现。
insert
update
OLD:表示”旧”的数据对象。在下列的操作时会出现。
update
delete

如果你想取得在线手册,同样的,你可以使用”help create trigger”来取得创建触发器的语法。

创建触发器语法如下:

1

2

3

4

5

6

7

8

mysql> help create trigger

Name: 'CREATE TRIGGER'

Description:

Syntax:

CREATE

[DEFINER = { user | CURRENT_USER }]

TRIGGER trigger_name trigger_time trigger_event

ON tbl_name FOR EACH ROW trigger_body

在创建触发器时,有下列的步骤需预先知道或特别注意的:

  • 首先,创建触发器时,使用者必须要有SUPER的权限。
  • 和先前创建Stored Procedure一样,在创建触发器时,可以指定DEFINER。而在执行触发器的时候,会先检查DEFINER的设定。而该使用者必须要有三个权限:
  • SUPER的权限。
  • 如果使用OLD.[字段]或NEW.[字段],则必须要有SELECT数据表的权限。
  • 如果使用SET NEW.[拦位] = “值”,则必须要有UPDATE数据表的权限。
  • 指定DEFINER后,要再指定trigger的时间点是注册的事件。同时指定”for each row”,让每笔数据修改都触发MySQL的操作。
  • 最后,在begin和end的语法中,指定触发器要操作的行为。

再来,我们来看看几个创建触发器的范例:

范例一:新增后的触发器。

(after insert)

1

2

3

4

5

6

7

8

9

mysql> delimiter //

mysql> create trigger ai_t1

-> after insert

-> on t1

-> for each row

-> begin

-> insert into i1 values (new.id, new.name);

-> end//

mysql> delimiter ;

这个触发器就是在新增动作结束后,便将新增数据的id, name同步储存在i1的数据表中。

范例二:更新后的触发器。

(after update)

1

2

3

4

5

6

7

8

9

mysql> delimiter //

mysql> create trigger au_t1

-> after update

-> on t1

-> for each row

-> begin

-> insert into u1 values(old.id, old.name, new.id, new.name)//

-> end//

mysql> delimiter ;

这个触发器就是在更新动作结束后,便将新/旧的id, name数据,同步储存在u1的数据表中。

范例三:删除后的触发器。

(after delete)

1

2

3

4

5

6

7

8

9

10

11

mysql> delimiter //

mysql> drop trigger if exists ad_p//

mysql> create trigger ad_p

    -> after delete

    -> on p

    -> for each row

    -> begin

    -> insert into old_p values (old.id, old.no);

    -> delete from c where c.id=old.id;

    -> end//

mysql> delimiter ;

这个触发器就是在删除动作结束后,便将旧的id, no数据,同步储存在old_p的数据表中,同时,将数据表c中有关于被删除id的相关资料也一并删除(这样的行为雷同数据表的外来键delete cascade,但还多了一个logging的机制)。

看完范例后,你也可以开始在你的MySQL数据库中,创建一个触发器来玩玩啰。

再来我们要介绍MySQL的事件。

什么是”事件”?”事件”是数据库系统根据时间排程而执行的工作。
由于它是由”时间”来触发执行,所以,我们可以将”事件”视为是一种”暂时”的触发器。
事件是由一个特定的线程来管理,而拥有PROCESS权限的使用者则可以用”SHOW PROCESSLIST”指令来看目前执行的工作。

首先,我们可以先来检查MySQL的事件排程是否已经启动。

1

2

3

4

5

6

7

mysql> select @@event_scheduler;

+-------------------+

| @@event_scheduler |

+-------------------+

| OFF |

+-------------------+

1 row in set (0.00 sec)

如果没有启动,则你可以利用下面的指令将它开启。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

mysql> set global event_scheduler = ON;

mysql> select @@event_scheduler;

+-------------------+

| @@event_scheduler |

+-------------------+

| ON |

+-------------------+

1 row in set (0.00 sec)

mysql> show processlist;

+----+-----------------+-----------+------+---------+------+------------------------+------------------+

| Id | User | Host | db | Command | Time | State | Info |

+----+-----------------+-----------+------+---------+------+------------------------+------------------+

| 8 | event_scheduler | localhost | NULL | Daemon | 240 | Waiting on empty queue | NULL |

| 9 | root | localhost | NULL | Query | 0 | NULL | show processlist |

+----+-----------------+-----------+------+---------+------+------------------------+------------------+

2 rows in set (0.00 sec)

再来我们要看看创建事件的语法。

类似的指令,我们可以由”help create event”来取得创建事件的语法:

创建事件的语法如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

mysql> help create event

Name: 'CREATE EVENT'

Description:

Syntax:

CREATE

[DEFINER = { user | CURRENT_USER }]

EVENT

[IF NOT EXISTS]

event_name

ON SCHEDULE schedule

[ON COMPLETION [NOT] PRESERVE]

[ENABLE | DISABLE | DISABLE ON SLAVE]

[COMMENT 'comment']

DO event_body;

 

schedule:

AT timestamp [+ INTERVAL interval] ...

| EVERY interval

[STARTS timestamp [+ INTERVAL interval] ...]

[ENDS timestamp [+ INTERVAL interval] ...]

 

interval:

quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |

WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |

DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

在使用创建事件时,我们需要注意的地方如下:

1.     创建者(DEFINER):如之前预存函数/触发器的设定一样,使用者可以设定DEFINER。

2.     时间触发的次数:可分为一次性或多次触发。如果是一次性的触发,可使用”AT”;如果是多次的触发,则使用”EVERY”。

3.     触发的起始时间设定:可用”STARTS”来设定起始时间;”ENDS”来设定结束时间。

4.     时间间隔(interval):时间间隔的单位,可参考在线手册。

5.     保存事件:默认值是”ON COMPLETION NOT PRESERVE”。也就是在事件完成后(如果是多次触发事件,则是超过事件结束时间”ENDS”),该事件就会自动被删除。如果,你想保留这个事件,则必须指定”ON COMPLETION PRESERVE”。

再来,我们来看个创建事件的范例:

1

2

3

4

5

6

7

8

9

10

11

mysql> set global event_scheduler=on;

mysql> grant event on stanley.* to 'bob'@'localhost';

mysql> create

-> definer='stanley'@'localhost'

-> event if not exists event_name

-> on schedule every 10 second

-> on completion preserve

-> enable

-> comment 'Trigger this event in every 10 seconds.'

-> do

-> select now() into outfile '/tmp/now.txt';

这个事件就是每十秒触发一次的事件,其动作是将系统时间储存在外部的档案上(/tmp/now.txt),而且这是一个没有设定结束时间的事件。

结论:

触发器与事件是一个好用的工具,数据库管理师可以将商业逻辑包装在数据库中,则可以减少应用程序的工作,并可确保跨应用程序中,仍可确保相同的”数据”逻辑,常见的用途是对数据库的稽核。但如开宗明义所说的,触发器是把双面刃,滥用的情况下,反而会造成资源的耗损,不可不查也~

 

在线客服