关注微信公众号:CodingTechWork,一起学习进步。

引言

  一般在使用定时任务时,我们首先会想到使用@Scheduled注解去给某个任务设置定时时间进行定时执行。当定时任务过多时,或者有增删改查需求时,@Scheduled注解将无法满足我们的需求。本文一起学习总结Quartz定时框架的使用。

Quartz介绍

概述

Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; jobs whose tasks are defined as standard Java components that may execute virtually anything you may program them to do. The Quartz Scheduler includes many enterprise-class features, such as support for JTA transactions and clustering.
Quartz is freely usable, licensed under the Apache 2.0 license.

  Quartz是OpenSymphony开源的一个项目,是一个由Java编写的开源作业调度框架。

特点

  1. 支持分布式高可用,我们需要某个定时任务在多个节点中只有某个节点可以执行时,就需要Quartz来实现,否则使用@Scheduled等方式会造成所有节点都执行一遍。
  2. 支持持久化,Quartz有专门的数据表来实现定时任务的持久化。
  3. 支持多任务调度和管理,Quartz可以在数据库中存储多个定时任务进行作业调度,可以实现定时任务的增删改查等管理。

组成

  Quartz由三部分组成:

  1. 任务:JobDetail
  2. 触发器:Trigger(分为SimpleTrigger和CronTrigger)
  3. 调度器:Scheduler

JobDetail

  JobDetail主要由JobKey(job的名字name和分组group)、JobClass、JobDataMap(任务相关的数据)、JobBuilder组成。常用的是前几个。

JobDetail源码

package org.quartz;import java.io.Serializable;public interface JobDetail extends Serializable, Cloneable {JobKey getKey();String getDescription();Class<? extends Job> getJobClass();JobDataMap getJobDataMap();boolean isDurable();boolean isPersistJobDataAfterExecution();boolean isConcurrentExectionDisallowed();boolean requestsRecovery();Object clone();JobBuilder getJobBuilder();
}

JobDetail示例

     Map<String,String> jobData = new HashMap<>();String jobName = "schedulerJob";String jobGroup = "schedulerGroup";jobData.put("key00", "value00");JobDetail jobDetail = JobBuilder.newJob(SchedulerJob.class).withIdentity(jobName, jobGroup).usingJobData("key01", "value01").usingJobData(jobData).storeDurably().build();

Trigger

  Trigger规定触发执行Job实现类,主要有SimpleTrigger和CronTrigger两个实现类。Trigger由以下部分组成:

  1. TriggerKey(job的名字name和分组group)
  2. JobDataMap(Trigger相关的数据,同JobDetail中JobDataMap,存相同key,若value不同,会覆盖前者。)
  3. ScheduleBuilder(有CronScheduleBuilder、SimpleScheduleBuilder、CalendarIntervalScheduleBuilder、DailyTimeIntervalScheduleBuilder常用前2种。)

    Trigger示例

 //SimpleScheduleBuilderString triggerName = "schedulerJob";String triggerGroup = "schedulerGroup";Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerName, triggerGroup).withSchedule(SimpleScheduleBuilder).repeatSecondlyForever(1).withIntervalInSeconds(0).withRepeatCount(0)).startNow().build();//CronScheduleBuilderString triggerName2 = "schedulerJob2";String triggerGroup2 = "schedulerGroup2";String jobTime = "0 0 * * * ?";Trigger trigger2 = TriggerBuilder.newTrigger().withIdentity(triggerName2, triggerGroup2).startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND)).withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).startNow().build();

Scheduler

  调度器就是为了读取触发器Trigger从而触发定时任务JobDetail。可以通过SchedulerFactory进行创建调度器,分为StdSchedulerFactory(常用)和DirectSchedulerFactory两种。

  1. StdSchedulerFactory使用一组属性(放在配置文件中)创建和初始化调度器,然后通过getScheduler()方法生成调度程序。
  2. DirectSchedulerFactory不常用,容易硬编码。

    Scheduler示例

 //建好jobDetail,trigger... ...//StdSchedulerFactory方式,用的多SchedulerFactory schedulerFactory = new StdSchedulerFactory();Scheduler schedulerStd = schedulerFactory.getScheduler();//DirectSchedulerFactory方式DirectSchedulerFactory directSchedulerFactory = DirectSchedulerFactory.getInstance();Scheduler schedulerDir=directSchedulerFactory.getScheduler();//执行调度schedulerStd.scheduleJob(jobDetail, trigger);schedulerStd.start();

Cron表达式

  定时任务离不开Cron表达式设置具体执行时间或执行周期,Cron表达式是一个字符串,一般有两种表达:

  1. 秒 分 小时 日 月 星期 年
  2. 秒 分 小时 日 月 星期

其中,年份即为可选的,所以一般表达式为6-7个域,每个域以空格分开。其中的星期除了可以使用英文缩写,也可以用数字1-7数字来表示,注意1表示的是星期日7表示的星期六

  • *:星号,表示每个字段对应的时间域的每一个,如在日中,就是表示每天。
  • ?:问号,只能在日期和星期字段中使用,表示无意义的值,等价于点位符。
  • -:减号,表示一个范围,如在分钟中使用5-8,则表示5-8分钟,即5、6、7、8分钟。
  • ,:逗号,表示一个列表值,如在星期中星期一和星期三使用MON,WED,也可以使用数字来表示:1,3
  • /:斜杠,使用x/y来表示一个等步长序列,x表示起始值,y表示步长值。如在秒字段中使用0/15,表示从0秒开始,每15秒增量,即0秒,15秒,30秒,45秒,这种就可以理解为每15秒执行任务。
  • L:只能在日期和星期字段中使用,表示Last。在日期中,L表示月份的最后一天,如1月中的31日;在星期中,L表示星期六(或数字7)。
  • W:只能在日期字段中使用,表示离该日期最近的工作期,不可以跨月。如10W,表示离该月10号最近的工作日,若10号为星期六,则匹配9号星期五;若10号为星期日,则匹配11号星期一;若10号为星期一,则匹配10号星期一。LW组合表示该月的最后一个工作日。
  • C:只能在日期和星期字段中使用,表示Calendar,即计划所关联的日期,若日期未被关联,则等价于关联所有日期。如日期中使用4C,表示日期4号以后的第一天;星期中使用1C,表示星期日后的第一天。
  • #:井号只能在星期字段中使用,表示当月某个工作日。如6#2表示当月的第二个星期五(其中,6表示星期五,#3表示当月的第二个).

    Cron示例

Cron表达式 说明
0 0 * * * ? 每小时0分0秒运行
0 0 1 * * ? 每天01:00:00运行运行
0 0 1 * * ? * 每天01:00:00运行运行,同上
0 0 1 * * ? 2021 2021年每天01:00:00运行
0 * 10 * * ? 每天10点-11点之间每分钟运行一次,开始于10:00:00,结束于10:59:00
0 0/5 10 * * ? 每天10点-11点之间每5分钟运行一次,开始于10:00:00,结束于10:59:00
0 0/5 10,15 * * ? 每天10点-11点之间每5分钟运行一次,每天15点-16点之间每5分钟运行一次
0 0-10 10 * * ? 每天10:00-10:10之间每分钟运行
0 10 1 ? * MON-FRI 每周一,二,三,四,五的1:10分运行
0 10 1 1 * ? 每月1日的1:10分运行
0 10 1 L * ? 每月最后一天1:10分运行
0 10 1 ? * 6L 每月最后一个星期五1:10分运行
0 10 1 ? * 6#3 每月第3个星期五1:10分运行

Quartz增删改查模板

QuartzService接口类

package com.andya.selfcode.quartzservice;import org.springframework.scheduling.quartz.QuartzJobBean;
import java.util.List;
import java.util.Map;/*** @author Andya* @date 2021/4/01*/
public interface QuartzService {/*** 增加一个任务job* @param jobClass  任务job实现类* @param jobName   任务job名称(保证唯一性)* @param jobGroupName  任务job组名* @param jobTime   任务时间间隔(秒)* @param jobTimes  任务运行次数(若<0,则不限次数)* @param jobData   任务参数*/void addJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, int jobTime,int jobTimes, Map jobData);/*** 增加一个任务job* @param jobClass  任务job实现类* @param jobName   任务job名称(保证唯一性)* @param jobGroupName  任务job组名* @param jobTime   任务时间表达式* @param jobData   任务参数*/void addJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, String jobTime, Map jobData);/*** 修改一个任务job* @param jobName 任务名称* @param jobGroupName  任务组名* @param jobTime   cron时间表达式*/void updateJob(String jobName, String jobGroupName, String jobTime);/*** 删除一个任务job* @param jobName* @param jobGroupName*/void deleteJob(String jobName, String jobGroupName);/*** 暂停一个任务job* @param jobName* @param jobGroupName*/void pauseJob(String jobName, String jobGroupName);/*** 恢复一个任务job* @param jobName* @param jobGroupName*/void resumeJob(String jobName, String jobGroupName);/*** 立即执行一个任务job* @param jobName* @param jobGroupName*/void runAJobNow(String jobName, String jobGroupName);/*** 获取所有任务job* @return*/List<Map<String, Object>> queryAllJob();/*** 获取正在运行的任务job* @return*/List<Map<String, Object>> queryRunJob();}

QuartzServiceImpl实现类

package com.andya.selfcode.quartz.service;import com.andya.selfcode.quartz.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Service;import javax.annotation.PostConstruct;
import java.util.*;/*** @author Andya* @date 2021/4/01*/
@Slf4j
@Service
public class QuartzServiceImpl implements QuartzService {@Autowiredprivate Scheduler scheduler;@PostConstructpublic void startScheduler() {try {scheduler.start();} catch (SchedulerException e) {e.printStackTrace();}}/*** 增加一个job** @param jobClass*            任务实现类* @param jobName*            任务名称* @param jobGroupName*            任务组名* @param jobTime*            时间表达式 (这是每隔多少秒为一次任务)* @param jobTimes*            运行的次数 (<0:表示不限次数)* @param jobData*            参数*/@Overridepublic void addJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, int jobTime,int jobTimes, Map jobData) {try {// 任务名称和组构成任务keyJobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();// 设置job参数if(jobData!= null && jobData.size()>0){jobDetail.getJobDataMap().putAll(jobData);}// 使用simpleTrigger规则Trigger trigger = null;if (jobTimes < 0) {trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName).withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withIntervalInSeconds(jobTime)).startNow().build();} else {trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName).withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withIntervalInSeconds(jobTime).withRepeatCount(jobTimes)).startNow().build();}log.info("jobDataMap: {}", jobDetail.getJobDataMap().getWrappedMap());scheduler.scheduleJob(jobDetail, trigger);} catch (SchedulerException e) {e.printStackTrace();throw new BaseException("add job error!");}}/*** 增加一个job** @param jobClass*            任务实现类* @param jobName*            任务名称(建议唯一)* @param jobGroupName*            任务组名* @param jobTime*            时间表达式 (如:0/5 * * * * ? )* @param jobData*            参数*/@Overridepublic void addJob(Class<? extends QuartzJobBean> jobClass, String jobName, String jobGroupName, String jobTime, Map jobData) {try {// 创建jobDetail实例,绑定Job实现类// 指明job的名称,所在组的名称,以及绑定job类// 任务名称和组构成任务keyJobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();// 设置job参数if(jobData!= null && jobData.size()>0){jobDetail.getJobDataMap().putAll(jobData);}// 定义调度触发规则// 使用cornTrigger规则// 触发器keyTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName).startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND)).withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).startNow().build();// 把作业和触发器注册到任务调度中scheduler.scheduleJob(jobDetail, trigger);log.info("jobDataMap: {}", jobDetail.getJobDataMap());} catch (Exception e) {e.printStackTrace();throw new BaseException("add job error!");}}/*** 修改 一个job的 时间表达式** @param jobName* @param jobGroupName* @param jobTime*/@Overridepublic void updateJob(String jobName, String jobGroupName, String jobTime) {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);log.info("new jobTime: {}", jobTime);trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).build();// 重启触发器scheduler.rescheduleJob(triggerKey, trigger);} catch (SchedulerException e) {e.printStackTrace();throw new BaseException("update job error!");}}/*** 删除任务一个job** @param jobName*            任务名称* @param jobGroupName*            任务组名*/@Overridepublic void deleteJob(String jobName, String jobGroupName) {try {scheduler.deleteJob(new JobKey(jobName, jobGroupName));} catch (Exception e) {e.printStackTrace();throw new BaseException("delete job error!");}}/*** 暂停一个job** @param jobName* @param jobGroupName*/@Overridepublic void pauseJob(String jobName, String jobGroupName) {try {JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);scheduler.pauseJob(jobKey);} catch (SchedulerException e) {e.printStackTrace();throw new BaseException("pause job error!");}}/*** 恢复一个job** @param jobName* @param jobGroupName*/@Overridepublic void resumeJob(String jobName, String jobGroupName) {try {JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);scheduler.resumeJob(jobKey);} catch (SchedulerException e) {e.printStackTrace();throw new BaseException("resume job error!");}}/*** 立即执行一个job** @param jobName* @param jobGroupName*/@Overridepublic void runAJobNow(String jobName, String jobGroupName) {try {JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);scheduler.triggerJob(jobKey);} catch (SchedulerException e) {e.printStackTrace();throw new BaseException("run a job error!");}}/*** 获取所有计划中的任务列表** @return*/@Overridepublic List<Map<String, Object>> queryAllJob() {List<Map<String, Object>> jobList = null;try {GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);jobList = new ArrayList<Map<String, Object>>();for (JobKey jobKey : jobKeys) {log.info("maps: {}", scheduler.getJobDetail(jobKey).getJobDataMap().getWrappedMap());List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);for (Trigger trigger : triggers) {Map<String, Object> map = new HashMap<>();map.put("jobName", jobKey.getName());map.put("jobGroupName", jobKey.getGroup());map.put("description", "触发器:" + trigger.getKey());Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());map.put("jobStatus", triggerState.name());if (trigger instanceof CronTrigger) {CronTrigger cronTrigger = (CronTrigger) trigger;String cronExpression = cronTrigger.getCronExpression();map.put("jobTime", cronExpression);}jobList.add(map);}}} catch (SchedulerException e) {e.printStackTrace();throw new BaseException("query all jobs error!");}return jobList;}/*** 获取所有正在运行的job** @return*/@Overridepublic List<Map<String, Object>> queryRunJob() {List<Map<String, Object>> jobList = null;try {List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();jobList = new ArrayList<Map<String, Object>>(executingJobs.size());for (JobExecutionContext executingJob : executingJobs) {Map<String, Object> map = new HashMap<String, Object>();JobDetail jobDetail = executingJob.getJobDetail();JobKey jobKey = jobDetail.getKey();Trigger trigger = executingJob.getTrigger();map.put("jobName", jobKey.getName());map.put("jobGroupName", jobKey.getGroup());map.put("description", "触发器:" + trigger.getKey());Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());map.put("jobStatus", triggerState.name());if (trigger instanceof CronTrigger) {CronTrigger cronTrigger = (CronTrigger) trigger;String cronExpression = cronTrigger.getCronExpression();map.put("jobTime", cronExpression);}jobList.add(map);}} catch (SchedulerException e) {e.printStackTrace();throw new BaseException("query run jobs error!");}return jobList;}}

Quartz使用方式

应用启动时自动调用

  写一个配置类,使用@Bean注解进行配置实例化。

QuartzConfig配置类

package com.andya.selfcode.quartz;import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;/*** @author Andya* @create 2021/04/01*/
@Configuration
@Service
public class QuartzConfig {@Beanpublic JobDetail scheduleJobDetail() {System.out.println("**************************************** scheduler job begin");JobDetail jobDetail = JobBuilder.newJob(SchedulerJob.class).withIdentity("schedulerJob").storeDurably().build();System.out.println("**************************************** scheduler job end");return jobDetail;}@Beanpublic Trigger scheduleJobDetailTrigger() {Trigger trigger = TriggerBuilder.newTrigger().forJob(scheduleJobDetail()).withIdentity("schedulerJob").withSchedule(SimpleScheduleBuilder.simpleSchedule().withRepeatCount(0)).startNow().build();System.out.println("schedulerJob trigger end");return trigger;}

SchedulerJob任务类增删

package com.andya.selfcode.quartz;import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.quartz.QuartzJobBean;/*** @author Andya* @create 2021/04/01*/
@Slf4j
public class SchedulerJob extends QuartzJobBean {@AutowiredQuartzService quartzService;@Value("${schedule.cron.withJob1}")private String cronTimeJob1;public String getCronTimeJob1() {return cronTimeJob1;}@Value("${schedule.cron.withJob2}")private String cronTimeJob2;public String getCronTimeJob1() {return cronTimeJob2;}@Overrideprotected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {try{//job1先删后增log.info("job1: delete scheduleWithJob1");quartzService.deleteJob("scheduleWithJob1", "scheduleWithJob1_Group1");log.info("job1: add scheduleWithJob1");quartzService.addJob(ScheduleWithJob1.class, "scheduleWithJob1","scheduleWithJob1_Group1", cronTimeJob1, null);//按小时定时的job先删后增log.info("job2: delete scheduleWithJob2");quartzService.deleteJob("scheduleWithJob2", "scheduleWithJob2_Group2");log.info("job2: add scheduleWithJob2");quartzService.addJob(ScheduleWithJob2.class, "scheduleWithJob2","scheduleWithJob2_Group2", cronTimeJob2, null);} catch (Exception e) {log.error("quartz service scheduler job failed!");e.printStackTrace();}}
}

具体Job任务类

ScheduleWithJob1类

package com.andya.selfcode.quartz;import com.andya.selfcode.service.ScheduleJobService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;import java.time.LocalDateTime;/*** @author Andya* @create 2021/04/01*/
@Slf4j
public class ScheduleWithJob1 extends QuartzJobBean {@AutowiredScheduleJobService scheduleJobService;@Overrideprotected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException{System.out.println("start schedule job1: " + LocalDateTime.now());try {scheduleJobService.scheduleWithJob1();} catch (Exception e) {e.printStackTrace();}}
}

ScheduleWithJob2类

package com.andya.selfcode.quartz;import com.andya.selfcode.service.ScheduleJobService;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;import java.time.LocalDateTime;/*** @author Andya* @create 2021/04/01*/
public class ScheduleWithJob2 extends QuartzJobBean {@AutowiredScheduleJobService scheduleJobService;@Overrideprotected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {try {System.out.println("start schedule with job2: " + LocalDateTime.now());scheduleJobService.scheduleJob2();} catch (Exception e) {e.printStackTrace();}}
}

ScheduleJobService接口类

package com.andya.selfcode.service;/*** @author Andya* @create 2021/04/01*/
public interface ScheduleJobService {/*** job1定时任务* @throws Exception*/void scheduleJob1() throws Exception;/*** job2定时任务* @throws Exception*/void scheduleJob2() throws Exception;
}

HTTP接口方式调用

  写一个controller层直接调用QuartzService接口类。

package com.andya.selfcode.quartz.controller;import com.andya.selfcode.quartz.bean.UpdateJobBean;
import com.andya.selfcode.quartz.bean.JobXXXBean;
import com.andya.selfcode.quartz.exception.BadRequestException;
import com.andya.selfcode.quartz.service.QuartzService;
import com.andya.selfcode.quartz.service.jobs.Job1;
import io.swagger.annotations.*;
import org.quartz.JobDataMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.Map;/*** @author Andya* @create 2021/04/01*/
@RestController
@Api(value = "quartz增删改查相关API")
@RequestMapping(value = "/quartz")
public class YarnFlexibleCapacityExpansionController {@AutowiredQuartzService quartzService;@ApiOperation(value = "使用quartz添加job")@RequestMapping(value = "/addJob/{jobUUID}", method = RequestMethod.POST)public void addQuartzJob(@ApiParam(name = "jobUUID") @PathVariable("jobUUID") String jobUUID,@ApiParam(name = "JobXXXBean") @RequestBody JobXXXBean jobXXXBean) {if (jobXXXBean.getOpenBean() != null) {JobDataMap jobDataMap = new JobDataMap();jobDataMap.put("key01", jobXXXBean.getKey01());jobDataMap.put("key02", jobXXXBean.getKey02());jobDataMap.put("key03", jobXXXBean.getKey03());jobDataMap.put("jobTimeCron", jobXXXBean.getJobTimeCron());jobDataMap.put("key04", jobXXXBean.getKey04());quartzService.addJob(Job1.class,jobUUID,jobUUID,jobXXXBean.getJobTimeCron(),jobDataMap);} else {throw new BadRequestException("参数错误");}}@ApiOperation(value = "使用quartz查询所有job")@RequestMapping(value = "/queryAllJob", method = RequestMethod.GET)public List<Map<String, Object>> queryAllQuartzJob() {List<Map<String, Object>> list = quartzService.queryAllJob();return list;}@ApiOperation(value = "使用quartz查询所有运行job")@RequestMapping(value = "/queryRunJob", method = RequestMethod.GET)public List<Map<String, Object>> queryRunQuartzJob() {List<Map<String, Object>> list = quartzService.queryRunJob();return list;}@ApiOperation(value = "使用quartz删除job")@RequestMapping(value = "/deleteJob/{jobUUID}", method = RequestMethod.DELETE)public void deleteJob(@ApiParam(name = "jobUUID") @PathVariable("jobUUID") String jobUUID) {quartzService.deleteJob(jobUUID, jobUUID);}@ApiOperation(value = "使用quartz修改job的cron时间")@RequestMapping(value = "/updateJob/{jobUUID}", method = RequestMethod.PUT)public void deleteJob(@ApiParam(name = "jobUUID") @PathVariable("jobUUID") String jobUUID,@ApiParam(name = "jobCronTime") @RequestBody UpdateJobBean updateJobBean) {quartzService.updateJob(jobUUID, jobUUID, updateJobBean.getJobCronTime());}
}/*** @author Andya* @create 2021/04/01*/
@ApiModel(value = "更新job cron时间参数")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UpdateJobBean {@ApiModelProperty(value = "jobTime的cron表达式", example = "0 0 1 * * ?")String jobCronTime;public String getJobCronTime() {return jobCronTime;}public void setJobCronTime(String jobCronTime) {this.jobCronTime = jobCronTime;}
}

Quartz数据表脚本

quartz初始化数据表的sql脚本如下。

-- 1.1. qrtz_blob_triggers : 以Blob 类型存储的触发器。
-- 1.2. qrtz_calendars:存放日历信息, quartz可配置一个日历来指定一个时间范围。
-- 1.3. qrtz_cron_triggers:存放cron类型的触发器。
-- 1.4. qrtz_fired_triggers:存放已触发的触发器。
-- 1.5. qrtz_job_details:存放一个jobDetail信息。
-- 1.6. qrtz_job_listeners:job监听器。
-- 1.7. qrtz_locks: 存储程序的悲观锁的信息(假如使用了悲观锁)。
-- 1.8. qrtz_paused_trigger_graps:存放暂停掉的触发器。
-- 1.9. qrtz_scheduler_state:调度器状态。
-- 1.10. qrtz_simple_triggers:简单触发器的信息。
-- 1.11. qrtz_trigger_listeners:触发器监听器。
-- 1.12. qrtz_triggers:触发器的基本信息。DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(190) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
CRON_EXPRESSION VARCHAR(120) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_SIMPROP_TRIGGERS(SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_NAME VARCHAR(190) NOT NULL,TRIGGER_GROUP VARCHAR(190) NOT NULL,STR_PROP_1 VARCHAR(512) NULL,STR_PROP_2 VARCHAR(512) NULL,STR_PROP_3 VARCHAR(512) NULL,INT_PROP_1 INT NULL,INT_PROP_2 INT NULL,LONG_PROP_1 BIGINT NULL,LONG_PROP_2 BIGINT NULL,DEC_PROP_1 NUMERIC(13,4) NULL,DEC_PROP_2 NUMERIC(13,4) NULL,BOOL_PROP_1 VARCHAR(1) NULL,BOOL_PROP_2 VARCHAR(1) NULL,PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(190) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB;CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(190) NULL,
JOB_GROUP VARCHAR(190) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB;CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB;CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB;CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);commit;

refer by
http://www.quartz-scheduler.org/

SpringBoot——Quartz定时框架的使用详解和总结相关推荐

  1. 定时任务框架APScheduler学习详解

    定时任务框架APScheduler学习详解 APScheduler简介 在平常的工作中几乎有一半的功能模块都需要定时任务来推动,例如项目中有一个定时统计程序,定时爬出网站的URL程序,定时检测钓鱼网站 ...

  2. spring框架 AOP核心详解

    AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...

  3. Quartz定时框架CronTrigger开发使用实例

    Quartz定时框架CronTrigger开发使用 public class HelloJob implements Job {public void execute(JobExecutionCont ...

  4. pythonmessage用法_django 消息框架 message使用详解

    前言 在网页应用中,我们经常需要在处理完表单或其它类型的用户输入后,显示一个通知信息给用户. 对于这个需求,Django提供了基于Cookie或者会话的消息框架messages,无论是匿名用户还是认证 ...

  5. java集合框架的结构_集合框架(Collections Framework)详解及代码示例

    简介 集合和数组的区别: 数组存储基础数据类型,且每一个数组都只能存储一种数据类型的数据,空间不可变. 集合存储对象,一个集合中可以存储多种类型的对象.空间可变. 严格地说,集合是存储对象的引用,每个 ...

  6. 网易邮箱大师如何定时发送 定时发送邮件方法步骤详解

    网易邮箱大师是我们日常使用邮箱的最佳软件,不仅能批量登录邮件,还能定时发送邮件,可谓功能齐全,很多小伙伴不知道如何定时发送邮件,那么接下来小编说的这篇文章肯定会对你有帮助. 操作步骤如下: 1.打开网 ...

  7. Android系统(96)---Android 数据交换解析框架Gson使用详解

    Android 数据交换解析框架Gson使用详解 Json 是一种文本形式的数据交换格式,比 xml 更为轻量.Json 的解析和生成的方式很多,在 Android 平台上最常用的类库有 Gson 和 ...

  8. python安装robotframework报错_Python3+RIDE+RobotFramework自动化测试框架搭建过程详解

    Python2.7已于2020年1月1日开始停用,之前RF做自动化都是基于Python2的版本. 没办法,跟随时代的脚步,我们也不得不升级以应用新的控件与功能. 升级麻烦,直接全新安装. 一.Pyth ...

  9. SpringBoot使用AOP,PointCut表达式详解以及使用

    SpringBoot使用AOP,PointCut表达式详解以及使用 1.相关注解 2.PointCut 表达式详解 2.1 execution: 2.1 within: 2.3. this: 2.4. ...

最新文章

  1. hosts和resolv.conf区别
  2. Java学习小程序(2)输出三个数中的最大值
  3. Android之玩转选项卡(TabHost、TabWidget、FrameLayout)
  4. Myeclipse 6.5 优化
  5. nasa注册_今天是黑洞星期五!
  6. python 无序列表中第k大元素_Python要求O(n)复杂度求无序列表中第K的大元素实例...
  7. 小甲鱼OD学习第18讲
  8. 【华为云技术分享】全WEB化开发体验,开发者新利器华为云CloudIDE即将揭秘
  9. SpringBoot2.1.15(26) WebFlux快速上手——响应式Spring的道法术器
  10. 2.C#面向对象基础属性
  11. 含有空格或者逗号的字符串反转最有效的办法——栈
  12. 没了美国EDA软件,我们就不能做芯片?
  13. 企业微信 之 网页鉴权并与公司后台关联
  14. ‘dtools’不是内部或外部命令,也不是可运行的程序或批处理文件,个人解决方案
  15. 在Python中建立N维数组并赋初值
  16. 工厂方法 VS 抽象工厂
  17. 01Cadence Allegro做PCB拼版
  18. 计算机主板会自动切断电源是怎么回事,主机启动一秒又自动断电一直循环 就只擦内存条...
  19. 怎样将计算机硬盘的资料彻底删除吗,3种技巧|如何从USB永久删除/清除文件
  20. Python简明教程--Set

热门文章

  1. Ubuntu 在终端下使用命令行打开pdf文件
  2. 让老照片重现光彩(一):Bringing Old Photos Back to Life
  3. selenium 页面经常改变元素_selenium用jquery改变元素属性
  4. pcfg 自然语言处理_自然语言处理导航
  5. html5背景图片设置大小_web前端学习之HTML5前端开发的特点
  6. 心怡哇1.0.版本一个女生的网站xinyiwa模板 ,WordPress主题1.0女性资讯模板主题
  7. 领航服务器系统,应用领航:盘点那些年我们一起追过的OS
  8. 如何腾出计算机内存,教你如何正确腾出手机内存,尤其是生活在易门的你,必学!...
  9. java bmp转jpg,在java中将bmp转换为jpg
  10. 动态规划 1.背包问题