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

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

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

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

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

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

示例配置:

yaml 复制代码
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 需要持久化任务状态,添加:

java 复制代码
@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:

java 复制代码
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 的关键:

java 复制代码
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的持久化配置: blog.csdn.net/Jeffhan_jav...

相关推荐
JustHappy4 小时前
古法编程秘籍(二):什么是代码模块化?别背概念,把房间收拾明白就够了
前端·后端
小江的记录本4 小时前
【JVM虚拟机】堆内存分代模型:年轻代(Eden+Survivor)、老年代、元空间Metaspace(附《思维导图》+《面试高频考点清单》)
java·前端·jvm·后端·python·spring·面试
IT_陈寒8 小时前
Python闭包里藏的这个坑,差点让我加班到凌晨
前端·人工智能·后端
IT_陈寒8 小时前
Java注解空指针?这个坑我踩得莫名其妙
前端·人工智能·后端
土狗TuGou9 小时前
SQL内功笔记 · 第8篇:事务的四大特性与隔离级别
数据库·笔记·后端·sql·mysql·oracle
ZengLiangYi9 小时前
React Query + REST API 最佳实践
javascript·后端·react.js
星浩AI9 小时前
项目实战:合同智能审批 · LangGraph + HITL 人机协同方案 [有源码]
后端·langchain·agent
JavaGuide9 小时前
Codex 接入第三方模型 DeepSeek、GLM、Kimi 教程:CC-Switch 和 Codex++ 两种方案对比
后端·ai编程
ZengLiangYi9 小时前
Fastify 加 Electron:把 Web 服务嵌进桌面应用
前端·javascript·后端
李白你好10 小时前
页面资产梳理 · 技术指纹识别 · Spring 端点探测
java·后端·spring