mysql菜鸟教程
16.5 创建定时任务
在上一节中,我们了解了 MySQL 事件调度器的基本概念和启用方法。本节将通过多个实际案例,手把手教你如何创建不同类型的定时任务,包括一次性任务和周期性重复任务,并介绍任务的管理与监控技巧。
一、回顾:事件调度器的核心语法
创建事件的完整语法如下(摘自上一节):
CREATE EVENT [IF NOT EXISTS] 事件名 ON SCHEDULE 调度规则 [ON COMPLETION [NOT] PRESERVE] [ENABLE | DISABLE] [COMMENT '描述'] DO SQL语句;
调度规则 可以是 AT(一次性)或 EVERY(重复)。
ON COMPLETION PRESERVE 表示事件执行后保留(对重复事件通常需要),默认是 NOT PRESERVE,即执行一次后自动删除。
ENABLE/DISABLE 控制事件是否激活。
二、实战:创建一次性任务
示例1:延时删除临时数据
假设我们有一个临时表 temp_cart,需要在创建后 1 小时自动清空。
CREATE EVENT clear_temp_cart ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO TRUNCATE TABLE temp_cart;
说明:
AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR 指定在当前时间的一小时后执行。
TRUNCATE 比 DELETE 更快,且释放空间。
示例2:在指定时间点执行一次任务
例如,在明年元旦凌晨 00:00 将所有用户积分清零。
CREATE EVENT reset_points ON SCHEDULE AT '2026-01-01 00:00:00' ON COMPLETION NOT PRESERVE -- 默认就是 NOT PRESERVE,可以不写 DO UPDATE users SET points = 0;
三、实战:创建周期性重复任务
示例3:每天凌晨清理过期日志
假设日志表 logs 保留最近 30 天数据,每天凌晨 3:00 自动清理。
CREATE EVENT clean_expired_logs ON SCHEDULE EVERY 1 DAY STARTS '2025-01-01 03:00:00' ON COMPLETION PRESERVE -- 重复任务必须保留 DO DELETE FROM logs WHERE log_date < CURDATE() - INTERVAL 30 DAY;
解释:
EVERY 1 DAY 表示每天执行一次。
STARTS 指定第一次执行的时间,如果省略则立即开始。
ON COMPLETION PRESERVE 保证任务执行后不会被删除。
示例4:每隔 10 分钟更新统计表
我们需要将订单总额实时统计到汇总表,但为了性能,可以每 10 分钟更新一次。
CREATE EVENT update_order_stats ON SCHEDULE EVERY 10 MINUTE STARTS CURRENT_TIMESTAMP ON COMPLETION PRESERVE DO UPDATE daily_summary ds SET total_orders = (SELECT COUNT(*) FROM orders WHERE order_date = ds.date), total_amount = (SELECT SUM(amount) FROM orders WHERE order_date = ds.date) WHERE ds.date = CURDATE();
示例5:每周一生成上周报表
假设每周一凌晨 2:00 自动生成上周的销售报表,并插入到 weekly_report 表。
CREATE EVENT generate_weekly_report ON SCHEDULE EVERY 1 WEEK STARTS '2025-01-06 02:00:00' -- 假设周一 ON COMPLETION PRESERVE DO BEGIN INSERT INTO weekly_report (week_start, week_end, total_sales) VALUES ( DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) + 7 DAY), DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) + 1 DAY), (SELECT SUM(amount) FROM orders WHERE order_date BETWEEN ...) ); END;
注意:DO 子句如果是多条语句,必须用 BEGIN ... END 包裹,并且通常需要在客户端中修改分隔符(DELIMITER)来创建。例如在 MySQL 命令行中:
DELIMITER // CREATE EVENT generate_weekly_report ON SCHEDULE EVERY 1 WEEK STARTS '2025-01-06 02:00:00' ON COMPLETION PRESERVE DO BEGIN INSERT INTO weekly_report (week_start, week_end, total_sales) VALUES ( ... ); END // DELIMITER ;
四、管理定时任务
查看事件状态
SHOW EVENTS\G;
输出包括事件名、状态(ENABLED/DISABLED)、类型(RECURRING/ONE TIME)、最后执行时间等。
查看事件的定义
SHOW CREATE EVENT clean_expired_logs\G;
暂停/启用事件
ALTER EVENT clean_expired_logs DISABLE; ALTER EVENT clean_expired_logs ENABLE;
修改事件的调度规则
例如将清理日志改为每天凌晨 4:00 执行:
ALTER EVENT clean_expired_logs ON SCHEDULE EVERY 1 DAY STARTS '2025-01-01 04:00:00';
删除事件
DROP EVENT IF EXISTS clean_expired_logs;
事件执行状态监控
要查看事件的历史执行情况,可以查询 mysql.event 表或使用 performance_schema 中的相关表(如 events_statements_current),但最简单的方法是:
在事件体内插入日志记录到自定义的日志表。
或者在事件执行后观察数据变化。
示例:在事件中添加日志输出(如果事件简单,可以不记录,但复杂事件建议记录)。
CREATE TABLE event_log (
log_id INT AUTO_INCREMENT PRIMARY KEY,
event_name VARCHAR(64),
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 在事件中插入日志
CREATE EVENT my_event
ON SCHEDULE EVERY 1 HOUR
DO
BEGIN
-- 业务逻辑
UPDATE ... ;
-- 记录执行
INSERT INTO event_log (event_name) VALUES ('my_event');
END;五、最佳实践与注意事项
时区一致性:确保 MySQL 服务器的时区设置正确,否则 CURDATE() 等函数可能不符合预期。可以在事件内使用 CONVERT_TZ 转换时区。
错误处理:事件内语句出错可能导致事件失败,并且不会自动重试。可以在事件体内使用 DECLARE CONTINUE HANDLER 捕获异常,并记录错误。
资源控制:避免事件执行时间过长,尤其是高峰时段。对于大批量数据操作,可以分批次处理(如 LIMIT 分批删除)。
事件调度器可靠性:如果 MySQL 重启,调度器状态由配置决定。确保 event_scheduler 设为 ON 并写入配置文件。
权限:创建事件需要 EVENT 权限,执行事件需要操作相关表的权限。
事件命名:采用清晰的前缀,例如 event_clean_、event_stats_,方便管理。
小结
通过 CREATE EVENT 可以轻松创建定时任务,替代外部 cron 脚本。
一次性任务使用 AT,周期性任务使用 EVERY。
使用 ALTER EVENT 修改任务属性,DROP EVENT 删除任务。
结合日志记录,可以监控任务的执行情况。
合理利用事件调度器,可以让数据库自动化维护工作变得简单高效。

发表评论
所有评论