SpringでQuartzをDBと一緒に使ってみる。

# はじめに
Springで定期実行をする場合は@Scheduledがお手軽に使えていいのですが、
後から時間の変更をする等の複雑な処理には対応していないようです。
そこでQuartzを導入しようとしたのですが情報が少なかったので備忘録として残します。

# 依存関係
* Lombok
* Spring Web
* Spring Data JPA
* Quartz Scheduler

# 設定
インメモリではなくデータベースを使用する。
```application.properties
spring.quartz.job-store-type=jdbc
```
　
Quartz用の設定はquartz.propertiesを作成する。
もしくはapplication.propertiesに下記をつけ足して書く。
```
spring.quartz.properties.org.quartz.....
```
　
各コネクションプール用の設定

https://github.com/quartz-scheduler/quartz/wiki/How-to-Use-DB-Connection-Pool

# SQL
各データベース用のSQLを選んでimport.sqlに書く。

https://github.com/quartz-scheduler/quartz/tree/master/quartz-core/src/main/resources/org/quartz/impl/jdbcjobstore

# ジョブ
```SimpleJob.class
@Slf4j
public class SimpleJob extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext context){
        log.info("SimpleJob Start");
        //ジョブの処理
        log.info("SimpleJob End");
    }
}
```

# サービスクラス
```SchedulerService.class
@Slf4j
@RequiredArgsConstructor
@Service
public class SchedulerService {
    @NonNull
    private SchedulerFactoryBean schedulerFactoryBean;
    @NonNull
    private ApplicationContext context;

    private final String name = "hoge";
    private final String group = "fuga";
    private final String cron = "*/10 * * * * * ?";//10秒ごとに実行

    public void insert() {//作成
        JobDetailFactoryBean jobDetailFB = new JobDetailFactoryBean();
        jobDetailFB.setApplicationContext(context);
        jobDetailFB.setJobClass(SimpleJob.class);
        jobDetailFB.setName(name);
        jobDetailFB.setGroup(group);//設定しない場合は自動的にDEFAULT_GROUPになる

        JobDataMap jobDataMap = new JobDataMap();
        //jobDataMap.put(key, value)でジョブへデータ受け渡し
        jobDetailFB.setJobDataMap(jobDataMap);
        jobDetailFB.afterPropertiesSet();

        CronTriggerFactoryBean cronTriggerFB = new CronTriggerFactoryBean();
        cronTriggerFB.setName(name);
        cronTrigger.setGroup(group);//設定しない場合は自動的にDEFAULT_GROUPになる
        cronTriggerFB.setStartTime(new Date());
        cronTriggerFB.setCronExpression(cron);
        cronTriggerFB.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
        //SimpleTriggerクラスの定数を設定

        try {
            cronTriggerFB.afterPropertiesSet();
            schedulerFactoryBean.getScheduler().scheduleJob(jobDetailFB.getObject(), cronTriggerFB.getObject());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    public void update() {//変更
        CronTriggerFactoryBean cronTriggerFB = new CronTriggerFactoryBean();
        cronTriggerFB.setName(name);
        cronTrigger.setGroup(group);//設定しない場合は自動的にDEFAULT_GROUPになる
        cronTriggerFB.setStartTime(new Date());
        cronTriggerFB.setCronExpression(cron);
        cronTriggerFB.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
        //SimpleTriggerクラスの定数を設定

        try {
            cronTriggerFB.afterPropertiesSet();
            schedulerFactoryBean.getScheduler().rescheduleJob(TriggerKey.triggerKey(name, group), cronTriggerFB.getObject());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    public void pause() {//停止
        try {
            schedulerFactoryBean.getScheduler().pauseJob(new JobKey(name, group));
        } catch (SchedulerException e) {
            log.error(e.getMessage(), e);
        }
    }

    public void resume() {//再開
        try {
            schedulerFactoryBean.getScheduler().resumeJob(new JobKey(name, group));
        } catch (SchedulerException e) {
            log.error(e.getMessage(), e);
        }
    }

    public void execute() {//一回のみ実行
        try {
            schedulerFactoryBean.getScheduler().triggerJob(new JobKey(name, group));
        } catch (SchedulerException e) {
            log.error(e.getMessage(), e);
        }
    }

    public void delete() {//削除
        try {
            schedulerFactoryBean.getScheduler().deleteJob(new JobKey(name, group));
        } catch (SchedulerException e) {
            log.error(e.getMessage(), e);
        }
    }
}
```
# まとめ
これでデータベースと連携させて複雑な定期実行も出来ると思います。
最新のSpringのリファレンスからQuartzが消えているのはどうしてなんだろう……。

# 参考
https://stackabuse.com/guide-to-quartz-with-spring-boot-job-scheduling-and-automation/