1. 程式人生 > >MySQL 事件(Event)與事件排程器(Event Scheduler)介紹

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

即可。