Erlo

Quartz定时任务持久化(服务重启后自动恢复)

2025-12-09 14:29:27 发布  
页面报错/反馈
收藏 点赞

Quartz 定时任务持久化(重启后自动恢复)

声明: 本文内容由 ChatGPT 协助生成,仅作为个人学习与记录之用。

Quartz 默认使用 RAMJobStore(内存存储),服务重启后任务会丢失。
要让定时任务在重启后仍然有效,必须启用:JDBCJobStore(数据库持久化)

本文说明如何在 Spring Boot 项目中配置 Quartz 持久化,使任务存入数据库并在重启后自动恢复。

1. 启用 Quartz 持久化(application.yml)

示例配置:

spring:
  quartz:
    job-store-type: jdbc   # 启用数据库持久化
    jdbc:
      initialize-schema: always   # 第一次启动自动建表,之后改为 never
    properties:
      org.quartz.scheduler.instanceName: QuartzScheduler
      org.quartz.scheduler.instanceId: AUTO
      org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
      org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
      org.quartz.jobStore.useProperties: false
      org.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. 如何验证持久化是否生效

  1. 创建一个 Job + Trigger

  2. 启动服务 → 任务执行正常

  3. 查看数据库 QRTZ_ 前缀的表,是否有记录

  4. 停止服务

  5. 再次启动

  6. 任务是否自动恢复执行

如能恢复,即持久化成功。

参考文章:
【Quartz】(一)定时框架Quartz的持久化配置: https://blog.csdn.net/Jeffhan_java/article/details/123532049

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认