MYSQL 定時任務

MySQL5.1.6起增長了事件調度器(Event Scheduler),可用來作定時執行某些特定任務,用於取代原先只能由操做系統的計劃任務來執行的工做。MySQL的事件調度器能夠精確到每秒執行一個任務,而操做系統的計劃任務只能精確到分鐘級別。對於對數據實時性要求比較高的應用很是合適。mysql

事件調度器也稱爲臨時觸發器(Temporal Triggers),由於事件調度器是基於特定時間週期觸發來執行某些任務,而觸發器(Triggers)是基於某個表所產生的事件觸發的。web

MySQL定時任務的實現方式有兩種:sql

  • 使用MySQL的event定時任務
    使用MySQL的事件計劃,首先須要在服務器開啓event_scheduler後才能處理。
  • 使用Linux的定時任務crontab

如何開啓事件計劃呢?shell

$ SHOW VARIABLES LIKE 'event_scheduler';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | OFF   |
+-----------------+-------+
1 row in set

若是執行命令後返回值爲OFF則表示目前事件計劃是處於關閉的狀態。json

開啓的方式也分爲兩種,臨時方式使用命令行或腳本操做,永久修改則須要修改MySQL主配置文件my.ini在其中添加event_schduler=1的配置後重啓MySQL。vim

臨時性修改只要不重啓MySQL在當前運行狀態下會直接生效,一旦重啓後則失效。ruby

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

事件調度器

要保證可以執行事件,就必須保證事件計劃是開啓狀態,事件計劃默認爲關閉狀態。bash

# 查看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的配置。服務器

事件任務

事件任務this

# 查看事件任務
$ 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

設置定時任務執行SQL語句

例如:從當日開始天天凌晨4點刪除fight表超過一個月的數據

計劃任務

DROP EVENT IF EXISTS event_fight_delete; 

CREATE EVENT event_fight_delete 
ON SCHEDULE EVERY 1 DAY STARTS DATE_ADD(DATE(CURDATE() + 1),  INTERVAL 4 HOUR)
DO
BEGIN
  DELETE FROM center_fight WHERE 1=1 AND  createdate < DATE_ADD(CURDATE(), INTERVAL -1 MONTH)
END

設置定時任務調用存儲過程

# 若計劃任務存在則刪除
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

在兩種計劃任務中,時間戳能夠是任意的TIMESTAMPDATETIME數據類型,時間戳須要大於當前時間。

在重複的計劃任務中,時間(單位)的數量能夠是任意非空(NOT NULL)的整數形式,時間單位是關鍵詞:YEARMONTHDAYHOURMINUTESECOND...

[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

錯誤處理

出現錯誤

[Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'information_schema.PROFILING.SEQ' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

解決方案

$ SELECT VERSION();
$ @@sql_mode;
$ SET sql_mode = (SELECT REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY' , ''));

出現提示

ERROR

# 在SQL中查詢計劃事件的狀態
$ SHOW VARIABLES LIKE 'event_scheduler'

# 在mysql程序的目錄下找到my.ini文件添加
$ vim my.ini
event_scheduler = 1
# 保存後重啓mysql服務

# 用腳原本實現
# 開啓event_scheduler sql指令:
SET GLOBAL event_scheduler = ON;
SET @@global.event_scheduler = ON;
SET GLOBAL event_scheduler = 1;
SET @@global.event_scheduler = 1;

$ 關閉event_scheduler指令:
SET GLOBAL event_scheduler = OFF;
SET @@global.event_scheduler = OFF;
SET GLOBAL event_scheduler = 0;
SET @@global.event_scheduler = 0;

2人點贊

mysql

做者:JunChow520
連接:https://www.jianshu.com/p/917... 來源:簡書 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

相關文章
相關標籤/搜索