Quartz 定时任务持久化(重启后自动恢复)
声明: 本文内容由 ChatGPT 协助生成,仅作为个人学习与记录之用。
Quartz 默认使用 RAMJobStore(内存存储),服务重启后任务会丢失。
要让定时任务在重启后仍然有效,必须启用:JDBCJobStore(数据库持久化)
本文说明如何在 Spring Boot 项目中配置 Quartz 持久化,使任务存入数据库并在重启后自动恢复。
1. 启用 Quartz 持久化(application.yml)
示例配置:
spring:quartz:job-store-type: jdbc # 启用数据库持久化jdbc:initialize-schema: always # 第一次启动自动建表,之后改为 neverproperties:org.quartz.scheduler.instanceName: QuartzSchedulerorg.quartz.scheduler.instanceId: AUTOorg.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegateorg.quartz.jobStore.useProperties: falseorg.quartz.jobStore.tablePrefix: QRTZ_org.quartz.threadPool.threadCount: 10
注意:
initialize-schema: always只在第一次启动时用
第二次以后必须改为 never,避免自动重建表导致任务丢失。
- 数据库需先创建好,Quartz 会自动建表(第一次)。
2. 初始化数据库(Quartz 表结构)
Quartz 内置表结构 SQL,可在 quartz-x.x.jar 中找到:
路径:
org/quartz/impl/jdbcjobstore/
根据数据库选择:
| 数据库 | SQL 文件 |
|---|---|
| MySQL | tables_mysql_innodb.sql |
| PostgreSQL | tables_postgres.sql |
| Oracle | tables_oracle.sql |
执行后会生成 11 张表,例如:
-
QRTZ_JOB_DETAILS -
QRTZ_TRIGGERS -
QRTZ_CRON_TRIGGERS -
QRTZ_SIMPLE_TRIGGERS -
QRTZ_FIRED_TRIGGERS -
QRTZ_SCHEDULER_STATE -
QRTZ_LOCKS
...
这些表记录 Job/Trigger,实现持久化。
3. 可选:为 Job 启用持久化注解(存储 JobDataMap)
如果你的 Job 需要持久化任务状态,添加:
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class MyJob implements Job {...
}
功能说明:
| 注解 | 作用 |
|---|---|
| @PersistJobDataAfterExecution | 执行后的JobDataMap数据状态写回数据库 |
| @DisallowConcurrentExecution | 任务串行执行,避免读写冲突 |
@DisallowConcurrentExecution 的作用
防止同一个 Job 的多个实例并发执行。
也就是说:
Quartz 会等待当前 Job 执行完,才会执行下一次触发。
为什么需要这个注解?
Quartz 默认行为是:
-
假设你的 Job 计划每 5 秒 执行一次
-
但你的任务实际执行时间是 10 秒
那么:
-
Quartz 会在第 5 秒再并发启动一个 Job 实例
-
第 10 秒再启动一个
-
这样会导致同一个 Job 多实例并发执行
这在很多业务场景是危险的:
-
写数据库时造成脏数据
-
写文件导致冲突
-
调接口重复提交
-
修改共享变量时出并发问题
加上 @DisallowConcurrentExecution 后
Quartz 保证:
✔ 第一个任务没执行完
✔ Quartz 不会再启动第二个
✔ 任务之间严格串行执行
✔ 安全性强
@PersistJobDataAfterExecution 的作用
让你在 Job 里面修改的参数(JobDataMap)能被保存下来,下次执行还能继续用。
举个最简单的例子
你有个定时任务,每次执行想让计数器 count +1:
int count = data.getInt("count");
data.put("count", count + 1);
如果 没有 @PersistJobDataAfterExecution:
-
每次执行 count 都从 0 开始
-
因为 Quartz 不会把你更新的值保存下来
如果 加上 @PersistJobDataAfterExecution:
-
count 会变成 1、2、3、4...
-
Quartz 会把更新后的值写回数据库
-
服务重启后 count 也不会丢
只要你在 job 里对 JobDataMap 做写操作,想保存结果 → 就一定要加 @PersistJobDataAfterExecution + @DisallowConcurrentExecution。(防止并发造成的数据覆盖和丢失)
如果你只需要任务被保存,而不需要保存 JobDataMap,可以不加这两个注解。
4. 创建 Job 时必须设置 .storeDurably()
持久化 Job 的关键:
JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("job1", "group1").storeDurably() // ★★★★★ 必须,Job 才会存入数据库.build();
不加 storeDurably() 的 Job 会被当成“临时 Job”,服务重启后会丢失。
Trigger 默认会持久化,不需要额外配置。
5. 服务重启后自动恢复机制
Quartz 启动时会自动从以下表中加载任务:
-
QRTZ_JOB_DETAILS -
QRTZ_TRIGGERS -
QRTZ_CRON_TRIGGERS/QRTZ_SIMPLE_TRIGGERS
无需额外代码。
6. 如何验证持久化是否生效
-
创建一个 Job + Trigger
-
启动服务 → 任务执行正常
-
查看数据库 QRTZ_ 前缀的表,是否有记录
-
停止服务
-
再次启动
-
任务是否自动恢复执行
如能恢复,即持久化成功。
参考文章:
【Quartz】(一)定时框架Quartz的持久化配置: https://blog.csdn.net/Jeffhan_java/article/details/123532049