MySQL5.1.6起增加了事件調度器(Event Scheduler),可用來做定時執行某些特定任務,用於取代原先只能由操作系統的計劃任務來執行的工作。MySQL的事件調度器可以精確到每秒執行一個任務,而操作系統的計劃任務只能精確到分鐘級別。對於對數據實時性要求比較高的應用非常合適。
事件調度器也稱爲臨時觸發器(Temporal Triggers),因爲事件調度器是基於特定時間週期觸發來執行某些任務,而觸發器(Triggers)是基於某個表所產生的事件觸發的。
MySQL定時任務的實現方式有兩種:
- 常規使用MySQL的
event
定時任務 - 使用Linux的定時任務
crontab
事件調度器
要保證能夠執行事件,就必須保證事件計劃是開啓狀態,事件計劃默認爲關閉狀態。
# 查看MySQL版本
$ SELECT VERSION();
+------------+
| VERSION() |
+------------+
| 5.7.18-log |
+------------+
1 row in set
# 事件計劃是否開啓
$ SHOW VARIABLES LIKE 'event%'
$ SHOW VARIABLES LIKE 'event_scheduler';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| event_scheduler | ON |
+-----------------+-------+
1 row in set
# 查看事件任務是否開啓
$ SELECT @@event_scheduler;
+-------------------+
| @@event_scheduler |
+-------------------+
| ON |
+-------------------+
1 row in set
# 開啓事件計劃
$ SET GLOBAL event_scheduler=1
$ SET GLOBAL event_scheduler=ON
duler=1;
Query OK, 0 rows affected
# 關閉事件計劃
$ SET GLOBAL event_scheduler=0
在真實開發環境中會遇到MySQL服務重啓或斷電的情況,此時會出現事件調度器被關閉的情況。所有事件都不再起作用,解決的方式需要在MySQL的配置文件mysql.ini
中加入event_scheduler=ON
的配置。
事件任務
事件任務
# 查看事件任務
$ SHOW EVENTS;
Empty set
# 查看事件任務錯誤 - 權限不足
$ SELECT * FROM mysql.event
1142 - SELECT command denied to user 'username'@'127.0.0.1' for table 'event'
# 開啓事件任務
$ ALTER EVENT event_name ON COMPLETION PRESERVE ENABLE
# 關閉事件任務
$ ALTER EVENT event_name ON COMPLETION PRESERVE DISABLE
# 刪除事件
$ DROP EVENT [IF EXISTS] event_name
設置定時任務調用存儲過程
# 若計劃任務存在則刪除
DROP EVENT IF EXISTS event_name
# 創建計劃任務
CREATE EVENT event_name
ON SCHEDULE EVERY 10 second
STARTS TIMESTAMP '2018-07-12 00:00:00'
ON COMPLETION PRESERVE
DO
BEGIN CALL producer()
END
參數說明
ON SCHDULE schduler
定義執行的時間和時間間隔ON COMPLETION [NOT] PRESERVE
定義事件是一次性執行還是永久執行,默認爲一次性執行,即NOT PRESERVE
。
在事件中ON SCHEDULE
計劃任務中有2種設定的方式
- 用來完成單次計劃任務。
AT 時間戳
eg:5天后
AT CURRENT_TIMESTAMP + INTERVAL 5 DAY
eg:某時間點
AT TIMESTAMP '2018-07-12 12:00:00'
- 用來完成重複的計劃任務
EVERY 時間(單位)的數量 時間單位 [STARTS 時間戳] [ENDS時間戳]
eg:每隔1秒
EVERY 1 SECOND
eg:每隔10分鐘。
EVERY 10 MINUTE
eg:從2018-08-01 12:00:00開始每隔1天
EVERY 1 DAY STARTS '2018-08-01 12:00:00'
EVERY 10 second STARTS TIMESTAMP '2018-08-01 12:00:00'
eg:5天后開啓每天定時處理
EVERY 1 DAY START CURRENT_TIMESTAMP + INTERVAL 5 DAY
eg:每天定時處理5天后停止
EVERY 1 DAY ENDS CURRENT_TIMESTAMP + INTERVAL 5 DAY
在兩種計劃任務中,時間戳可以是任意的TIMESTAMP
和DATETIME
數據類型,時間戳需要大於當前時間。
在重複的計劃任務中,時間(單位)的數量可以是任意非空(NOT NULL)的整數形式,時間單位是關鍵詞:YEAR
、MONTH
、DAY
、HOUR
、MINUTE
、SECOND
...
[ON COMPLETION [NOT] PRESERVE]
ON COMPLETION
參數表示“當這個事件不會再發生的時候”,即當單次計劃任務執行完畢後或當重複性的計劃任務執行到了ENDS
階段。而PRESERVE
的作用是使事件在執行完畢後不會被DROP
掉,建議使用該參數,以便於查看EVENT
具體信息。
CREATE DEFINER=`root`@`localhost` EVENT `event_knapsacks_remember_expire`
ON SCHEDULE EVERY 1 MINUTE STARTS '2018-07-13 15:09:49'
ON COMPLETION PRESERVE ENABLE
COMMENT '每分鐘檢測揹包中換牌卡到期並每日自動減少'
DO
BEGIN
CALL produce_knapsacks_remember_expire();
END
存儲過程
DELIMITER $$
DROP PROCEDURE IF EXISTS procedure_name
CREATE PROCEDURE procedure_name()
BEGIN
INSERT INTO procedure_name(name, create_time) VALUES('name_value', now())
END $$
DELIMITER ;
-- 存儲過程 produce_knapsacks_remember_expire
-- 作用:判斷揹包中道具記牌卡,是否過期,且每日減一。
CREATE DEFINER=`root`@`localhost` PROCEDURE `produce_knapsacks_remember_expire`()
BEGIN
DECLARE pk INT DEFAULT 0;
DECLARE sec INT DEFAULT 0;
DECLARE days INT DEFAULT 0;
DECLARE expire INT DEFAULT 0;
DECLARE mc CURSOR FOR (SELECT id,TIMESTAMPDIFF(SECOND,effect_time,NOW()) AS diff,TIMESTAMPDIFF(SECOND,NOW(),expire_time) AS expire FROM knapsacks WHERE name='REMEBER' AND expired=0);
OPEN mc;
ml:LOOP
FETCH mc INTO pk,sec,expire;
IF(expire <= 0) THEN
UPDATE `knapsacks` SET `expired`=1 WHERE `id`=pk;
ELSE
IF(sec>0 && sec<=86400) THEN
SET days = 1;
ELSEIF(sec>86400) THEN
SET days=CEILING(sec/86400);
END IF;
UPDATE `knapsacks` SET `quantity`=`purchase`-days,`consume`=days WHERE `id`=pk;
END IF;
COMMIT;
END LOOP ml;
CLOSE mc;
END
給大佬遞茶:
作者:JunChow520
鏈接:MySQL定時任務
來源:簡書