博客 / 詳情

返回

Quartz定時任務持久化(服務重啓後自動恢復)

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

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.