MySQL 事件(Event)与事件调度器(Event Scheduler)介绍

前言

事件调度器是在 MySQL 5.1 中新增的另一个特色功能,可以作为定时任务调度器,取代部分原先只能用操作系统任务调度器才能完成的定时功能。而且 MySQL 的事件调度器可以实现每秒钟执行一个任务,这在一些对实时性要求较高的环境下就非常实用了。

事件调度器是定时触发执行的,在这个角度上也可以称作是”临时的触发器”。触发器只是针对某个表产生的事件执行一些语句,而事件调度器则是在某一个(间隔)时间执行一些语句。事件是由一个特定的线程来管理的,也就是所谓的”事件调度器”。启用事件调度器后,拥有 SUPER 权限的账户执行 SHOW PROCESSLIST 就可以看到这个线程了。通过设定全局变量event_scheduler 的值即可动态的控制事件调度器是否启用。

创建事件

语法

CREATE
    [DEFINER = { user | CURRENT_USER }]
    EVENT
    [IF NOT EXISTS]
    event_name
    ON SCHEDULE schedule
    [ON COMPLETION [NOT] PRESERVE]
    [ENABLE | DISABLE | DISABLE ON SLAVE]
    [COMMENT 'string']
    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}

语法说明:
- DEFINER:指定可执行该定时器的MySQL账号,user的格式是’user_name’@’host_name’,CURRENT_USER或CURRENT_USER(),注意,单引号是需要在语句中输入的。如果不指定,默认是DEFINER = CURRENT_USER。
- event_name:事件名称,最大64个字符,不区分大小写,MyEvent和myevent是一样的,命名规则和其他MySQL对象是一样的。
- ON SCHEDULE schedule:下文详细说明。
- [ON COMPLETION [NOT] PRESERVE]:可选,preserve是保持的意思,这里是说这个定时器第一次执行完成以后是否还需要保持,如果是NOT PRESERVE,该定时器只执行一次,完成后自动删除事件;没有NOT,该定时器会多次执行,可以理解为这个定时器是持久性的。默认是NOT PRESERVE。
- [ENABLE | DISABLE | DISABLE ON SLAVE]:可选,是否启用该事件,ENABLE-启用,DISABLE-禁用,可使用alter event语句修改该状态。DISABLE ON SLAVE是指在主备复制的数据库服务器中,在备机上也创建该定时器,但是不执行。
- COMMENT: 注释,必须用单引号括住。
- DO event_body:事件要执行的SQL语句,可以是一个SQL,也可以是使用BEGIN和END的复合语句,和存储过程相同。

事件的执行时间

ON SCHEDULE指定事件何时执行,执行的频率和执行的时间段,有AT和EVERY两种形式。

AT timestamp

AT timestamp用于只执行一次的事件。执行的时间由timestamp指定,timestamp必须包含完整的日期和时间,即年月日时分秒都要有。可以使用DATETIME或TIMESTAMP类型,或者可以转换成时间的值,例如“2018-01-21 00:00:00”。如果指定是时间是过去的时间,该事件不会执行,并生成警告。

mysql> SELECT NOW();
+---------------------+
| NOW()               |
+---------------------+
| 2018-01-21 11:38:21 |
+---------------------+
1 row in set (0.050 sec)

mysql> CREATE EVENT e_totals
    ->     ON SCHEDULE AT '2018-01-21 11:38:20'
    ->     DO INSERT INTO test.totals VALUES (NOW());
Query OK, 0 rows affected, 1 warning (0.02 sec)

mysql> show warnings\G
*************************** 1. row ***************************
  Level: Note
   Code: 1588
Message: Event execution time is in the past and ON COMPLETION  
         NOT PRESERVE is set. The event was dropped immediately 
         after creation.
1 row in set (0.01 sec)

这个只执行一次的事件,因为时间定义是过去的时间,所以不会执行,创建以后又被立即删除。可以使用CURRENT_TIMESTAMP指定执行时间,这样的话,事件创建成功会立即执行。

如果事件执行的时间是未来的某个时间点,可以使用+ INTERVAL interval指定具体时间。interval有数字(quantity)和时间单位(Unit of time)两部分组成,例如:2分10秒后执行,应写为 + INTERVAL ‘2:10’ MINUTE_SECOND。可用的时间单位有很多,列表如下:

unit 说明
YEAR
QUARTER 季度
MONTH
DAY
HOUR
MINUTE
WEEK
SECOND
YEAR_MONTH 年:月
DAY_HOUR 日:时
DAY_MINUTE 日:分
DAY_SECOND 日:秒
HOUR_MINUTE 时:分
HOUR_SECOND 时:秒
MINUTE_SECOND 分:秒

示例

这是一个最简单的示例,1小时后执行该事件:

CREATE EVENT myevent
    ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
    DO
      UPDATE myschema.mytable SET mycol = mycol + 1;

Every interval

如果需要让事件定时执行,使用Every这种方式。注意EVERY后边的interval没有+ INTERVAL,时间格式和单位和上面的相同。

示例:
EVERY 6 WEEK 每六周
EVERY 20 second 每20秒

EVERY后面可以跟可选的STARTSENDS,指定事件开始和结束时间,在这个时间段内,时间定时执行。STARTSENDS可同时指定,或者只指定STARTS,或两者都不指定。

示例:
EVERY 3 MONTH STARTS CURRENT_TIMESTAMP + INTERVAL 1 WEEK 一周以后开始,每隔三个月
EVERY 2 WEEK STARTS CURRENT_TIMESTAMP + INTERVAL ‘6:15’ HOUR_MINUTE 六个小时15分钟以后,每隔两周
EVERY 12 HOUR STARTS CURRENT_TIMESTAMP + INTERVAL 30 MINUTE ENDS CURRENT_TIMESTAMP + INTERVAL 4 WEEK 30分钟以后开始,4周后结束,每隔12个小时

示例

这个示例是每小时执行一次指定操作:

CREATE EVENT e_hourly
    ON SCHEDULE
      EVERY 1 HOUR
    COMMENT 'Clears out sessions table each hour.'
    DO
      DELETE FROM site_activity.sessions;

以下是个稍微复杂点的例子,用到了复合语句:

delimiter $$

CREATE EVENT e_daily
    ON SCHEDULE
      EVERY 1 DAY
    COMMENT 'Saves total number of sessions then clears the table each day'
    DO
      BEGIN
        INSERT INTO site_activity.totals (time, total)
          SELECT CURRENT_TIMESTAMP, COUNT(*)
            FROM site_activity.sessions;
        DELETE FROM site_activity.sessions;
      END $$

delimiter ;

存储过程中用到的变量、错误处理和流程控制(while,if……)语句在eventbody中都可以使用,有一点区别是,事件不能接收参数。如果需要,可以在事件中调用存储过程,通过存储过程传参数。

修改事件

语法

ALTER
    [DEFINER = { user | CURRENT_USER }]
    EVENT event_name
    [ON SCHEDULE schedule]
    [ON COMPLETION [NOT] PRESERVE]
    [RENAME TO new_event_name]
    [ENABLE | DISABLE | DISABLE ON SLAVE]
    [COMMENT 'string']
    [DO event_body]

这里的关键字含义和创建Event语句是一样的,很好理解,下面给出一些实例帮助大家理解(来自官方文档)。

原始的Event定义如下:

CREATE EVENT myevent
    ON SCHEDULE
      EVERY 6 HOUR
    COMMENT 'A sample comment.'
    DO
      UPDATE myschema.mytable SET mycol = mycol + 1;

下面的语句,将myevent从当前开始每6个小时执行,改为4个小时候每隔12个小时执行:

ALTER EVENT myevent
    ON SCHEDULE
      EVERY 12 HOUR
    STARTS CURRENT_TIMESTAMP + INTERVAL 4 HOUR;

在一个Alter Event语句中,可以修改Event的多个属性,下面的语句将myevent修改成1天后删除mytable表中的所有数据,只执行一次:

ALTER EVENT myevent
    ON SCHEDULE
      AT CURRENT_TIMESTAMP + INTERVAL 1 DAY
    DO
      TRUNCATE TABLE myschema.mytable;

禁用事件:

ALTER EVENT myevent DISABLE;

修改事件名称:

ALTER EVENT myevent RENAME TO yourevent;

更进一步,可以将事件从一个数据库移动到另外一个数据库:

ALTER EVENT olddb.myevent RENAME TO newdb.myevent;

查看事件

MySQL的information_schema提供了访问数据库元数据的方式。 元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。其中Events表中可以查看所有已定义的事件的具体信息,包括事件所属库名称、事件名称、事件类型、事件的完整定义、开始时间、INTERVAL定义、上一次执行时间等等。

示例:

mysql> SELECT * FROM EVENTS\G
*************************** 1. row ***************************
       EVENT_CATALOG: def
        EVENT_SCHEMA: ^^^^^^ --数据库名称
          EVENT_NAME: ev_xxzh_tranhistory
             DEFINER: ^^^^^^^^^^^
           TIME_ZONE: SYSTEM
          EVENT_BODY: SQL
    EVENT_DEFINITION: BEGIN
    call sp_xxzh_transhistory();
END
          EVENT_TYPE: RECURRING
          EXECUTE_AT: NULL
      INTERVAL_VALUE: 1
      INTERVAL_FIELD: DAY
            SQL_MODE: NO_ENGINE_SUBSTITUTION
              STARTS: 2017-10-19 05:30:00
                ENDS: NULL
              STATUS: SLAVESIDE_DISABLED
       ON_COMPLETION: PRESERVE
             CREATED: 2017-10-19 18:00:26
        LAST_ALTERED: 2017-10-19 18:00:26
       LAST_EXECUTED: NULL
       EVENT_COMMENT: 
          ORIGINATOR: 110
CHARACTER_SET_CLIENT: utf8
COLLATION_CONNECTION: utf8_general_ci
  DATABASE_COLLATION: utf8_general_ci

Events表中的字段名称含义都很清晰,这里不再详细描述。

删除事件

删除事件的语句很简单:

drop event myevent;

事件调度器

启动事件调度器

SET GLOBAL event_scheduler = ON;
SET @@global.event_scheduler = ON;
SET GLOBAL event_scheduler = 1;
SET @@global.event_scheduler = 1;

关闭事件调度器

SET GLOBAL event_scheduler = OFF;
SET @@global.event_scheduler = OFF;
SET GLOBAL event_scheduler = 0;
SET @@global.event_scheduler = 0;

查看事件调度器状态

show variables like "event_scheduler";

查询结果:

mysql> show variables like "event_scheduler";
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set (0.04 sec)

如果当前事件调度器是关闭的,使用上面启动事件调度器的命令打开即可。使用命令的方式打开,数据库服务器重新启动后,事件调度器会恢复到关闭状态。如果想要默认启动事件调度器,可以通过修改配置文件my.cnf实现。具体做法是打开my.cnf文件,在[mysqld]下面添加一行:

event_scheduler = ON

即可。

参考资料:
http://blog.51cto.com/visionsky/761339
https://dev.mysql.com/doc/refman/5.7/en/create-event.html
http://blog.csdn.net/jesseyoung/article/details/35257527

你可能感兴趣的:(MySQL数据库)