傳統依賴 Linux cron + 腳本執行定時 SQL,存在部署依賴重、多實例配置繁瑣、環境遷移易遺漏等問題。MySQL 5.1+ 內建 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 '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}
AT 一次性執行;EVERY 週期執行。STARTS 等同 STARTS CURRENT_TIMESTAMP (創建即執行首次)。DISABLE ON SLAVE:主庫創建同步到從庫時自動禁用,防止雙邊執行。EVENT 權限。time_zone,存儲為 UTC。跨時區部署需注意。SET GLOBAL event_scheduler = ON; -- 或 1
[mysqld]
event_scheduler = ON
OFF (0):關閉,不啟動調度線程 (預設)。ON (1):啟動,可動態切換。DISABLED:禁用,**僅啟動時指定有效**。運行時無法從 ON/OFF 切換為 DISABLED,也無法從 DISABLED 切換出。徹底禁用調度功能。SHOW PROCESSLIST; -- 可見 event_scheduler 線程
SHOW VARIABLES LIKE 'event_scheduler';
-- 每小時清理會話表
CREATE EVENT e_hourly_cleanup
ON SCHEDULE EVERY 1 HOUR
COMMENT 'Clears out sessions table each hour'
DO DELETE FROM site_activity.sessions;
-- 複雜邏輯:每5秒批量寫入
DELIMITER |
CREATE EVENT e_batch_insert
ON SCHEDULE EVERY 5 SECOND
DO BEGIN
DECLARE v INT DEFAULT 0;
WHILE v < 5 DO
INSERT INTO t1 VALUES (0);
UPDATE t2 SET s1 = s1 + 1;
SET v = v + 1;
END WHILE;
END |
DELIMITER ;
ALTER EVENT e_hourly_cleanup DISABLE; -- 暫停
ALTER EVENT e_hourly_cleanup ENABLE; -- 恢復
ALTER EVENT e_hourly_cleanup RENAME TO e_daily_cleanup;
DROP EVENT [IF EXISTS] e_batch_insert;
SELECT * FROM mysql.event;
SELECT * FROM information_schema.events;
SHOW EVENTS;
SHOW CREATE EVENT e_hourly_cleanup;
PREPARE/EXECUTE)。LOCK TABLES/UNLOCK TABLES、LOAD DATA/LOAD TABLE。INSERT DELAYED 不生效。DO 子句中不能包含 ALTER EVENT (創建成功但執行報錯)。SELECT ... INTO @var 或寫入臨時表/日志表。GET_LOCK()、行鎖或表鎖實現單例執行。CREATE TABLE daily_score_report (
report_date DATE PRIMARY KEY,
subject VARCHAR(20),
avg_score DECIMAL(5,2)
);
CREATE EVENT ev_daily_score_stat
ON SCHEDULE EVERY 1 DAY
STARTS CURRENT_DATE + INTERVAL 1 HOUR -- 每天凌晨1點
DO
INSERT INTO daily_score_report (report_date, subject, avg_score)
SELECT DATE_SUB(CURRENT_DATE, INTERVAL 1 DAY), subject, AVG(score)
FROM student_scores
WHERE score_date = DATE_SUB(CURRENT_DATE, INTERVAL 1 DAY)
GROUP BY subject
ON DUPLICATE KEY UPDATE avg_score = VALUES(avg_score);
DELIMITER //
CREATE PROCEDURE sp_generate_dynamic_event()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE v_subject VARCHAR(50);
DECLARE cur CURSOR FOR SELECT DISTINCT subject FROM student_scores;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
SET @sql = 'CREATE EVENT ev_dynamic_stat ON SCHEDULE EVERY 1 DAY DO BEGIN ';
OPEN cur;
read_loop: LOOP
FETCH cur INTO v_subject;
IF done THEN LEAVE read_loop; END IF;
SET @sql = CONCAT(@sql, 'CALL sp_calc_subject_avg(\'', v_subject, '\'); ');
END LOOP;
CLOSE cur;
SET @sql = CONCAT(@sql, 'END;');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
-- 定期調用此過程重建動態事件,或在課程表變更觸發器中調用
sql_mode 將作為執行時的模式。DEFINER 權限檢查,而非調用者。mysqldump --events 導出事件定義,遷移無感知。event_scheduler=ON 會執行)。建議主庫創建時指定 DISABLE ON SLAVE,由應用層控制從庫是否啟用。