动态更新(新增、修改、删除)定时,即新增一个JOB、修改已有JOB的调度(如名称、执行时间等),删除一个JOB。至于实现方法,本人用过两种,一是除了业务本身的JOB,再新增一个JOB来监听业务JOB是否有增、删、改,在这个监听JOB中修改业务JOB的调度;二是只需要业务本身的JOB,再新增修改业务JOB调度(增、删、改)的controller接口,如果需要修改业务JOB的调度,直接调用相应controller接口,即可实时修改过来。
- 方法1:除了业务本身的JOB;再新增一个JOB来监听业务JOB是否需要增、删、改,在这个监听JOB中修改业务JOB的调度。
场景:如用户在前端新增闹钟,可以设置闹钟的提醒事件和提醒时间,如7点提醒一次,8点提醒一次,......还可以设置是否为一次性事件或者循环。这种场景使用Schedule是不合理的,因为Schedule的cron是在程序中配置的,无法动态加载用户设置的。可以使用quartz调度。使用quartz调度,在@PostConstruct中一次性加载了现有的闹钟后,用户后面新增的闹钟又会获取不到。我的想法是用两个job,job1尽量实时的获取未加载的闹钟(如可以30s获取一次clock),job2执行clock,给clock一个标志位,0表示job2还没有加载,1表示已经被job2加载了。这样设计后,如果重启服务,job1只获取状态为0的clock,但是状态为1的clock可能还需要执行,所以@PostConstruct中应该做两件事,先获取状态为1的clock放在job2中,再启动job1去获取状态为0的clock。闹钟还应该支持删除和修改操作。
一、数据库:
设计两张表,t_job表存放闹钟调度,t_task表为真正需要执行的闹钟。
CREATE TABLE `t_clock_job` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`clock_id` int(11) DEFAULT NULL COMMENT '闹钟id',
`cron` varchar(255) DEFAULT NULL COMMENT 'cron表达式',
`status` tinyint(4) DEFAULT NULL COMMENT '是否被job加载,0未加载,1已加载',
`create_time` timestamp NULL DEFAULT NULL,
`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`is_delete` bit(1) DEFAULT NULL COMMENT '是否删除,1已删除,0未删除',
`is_update` bit(1) DEFAULT NULL COMMENT '是否被修改,0未修改,1已修改',
`start_time` timestamp NULL DEFAULT NULL COMMENT '闹钟开始时间',
`end_time` timestamp NULL DEFAULT NULL COMMENT '闹钟结束时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `t_clock_task` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`clock_id` int(11) DEFAULT NULL COMMENT '闹钟id',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`status` varchar(255) DEFAULT NULL COMMENT '执行结果,SUCCESS,ERROR,READY,RUNNING',
`error_msg` varchar(255) DEFAULT NULL COMMENT '错误信息',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
现插入两个闹钟:
INSERT INTO `t_clock_job` VALUES ('1', '1', '0 0/1 * * * ? ', '0', '2019-06-25 14:12:57', '2019-06-25 14:44:04', '', '', '2019-06-25 10:45:26', '2019-06-26 10:45:30');
INSERT INTO `t_clock_job` VALUES ('4', '2', '0/30 0/1 * * * ? ', '0', null, '2019-06-25 16:17:30', '', '', '2019-06-25 16:17:06', '2019-06-26 16:17:09');
一个闹钟一分钟运行一次,一个30s运行一次。
二、说明:
如果前端需要循环执行,则往t_clock_job表插入数据,如果只是一次性任务,只需要往t_clock_task表插入数据即可。对于循环任务,一共有以下几个调度:
1、获取已被加载的job:status=1 and is_delete = 0;
2、获取未被加载的job:status = 0 and is_delete = 0;
3、获取被删除的job:is_delete = 1;
4、获取被修改的job,主要是修改它的启动结束时间和定时时间,未被加载的即使被修改了,加载后也会按照修改后的参数来执行,所以:status =1 and is_delete=0 and is_update =1。
其中,2和4执行后,该job的staus更新为1,is_update更新为0。
三、代码:
1、常量:
package com.demo.common;
/**
* @Description:JOB状态
*/
public class JobStatus {
public static Short UNEXECUTE = 0;
public static Short EXECUTE = 1;
}
package com.demo.common;
public enum TaskStatus {
READY,
RUNNING,
WAITTING,
SUCCESS,
ERROR
}
2、module:
package com.demo.module;
import java.io.Serializable;
import java.util.Date;
public class ClockJob implements Serializable{
/**
*
*/
private static final long serialVersionUID = 7480418920143777224L;
private Integer id;
private Integer clockId;
private String cron;
private Short status;
private Date createTime;
private Boolean isDelete;
private Boolean isUpdate;
private Date startTime;
private Date endTime;
/*省略所有get与set方法*/
}
package com.demo.module;
import java.io.Serializable;
import java.util.Date;
public class ClockTask implements Serializable{
/**
*
*/
private static final long serialVersionUID = 5140231292084278416L;
private Integer id;
private Integer clockId;
private Date createTime;
private Date updateTime;
private String status;
private String errorMsg;
/*省略所有get与set方法*/
}
3、serviceImpl:
package com.demo.service.Impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo.dao.ClockJobMapper;
import com.demo.module.ClockJob;
import com.demo.service.ClockJobService;
@Service("clockJobService")
public class ClockJobServiceImpl implements ClockJobService{
@Autowired
private ClockJobMapper clockJobMapper;
@Override
public List<ClockJob> getLoadedJobs() {
return clockJobMapper.getLoadedJobs();
}
@Override
public List<ClockJob> getUnExecutedJobs() {
return clockJobMapper.getUnExecutedJobs();
}
@Override
public void updateFlag(ClockJob clockJob) {
clockJobMapper.updateFlag(clockJob);
}
@Override
public List<ClockJob> getDeleteJobs() {
return clockJobMapper.getDeleteJobs();
}
@Override
public List<ClockJob> getUpdateJobs() {
return clockJobMapper.getUpdateJobs();
}
}
package com.demo.service.Impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo.dao.ClockTaskMapper;
import com.demo.module.ClockTask;
import com.demo.service.ClockTaskService;
@Service("clockTaskService")
public class ClockTaskServiceImpl implements ClockTaskService{
@Autowired
private ClockTaskMapper clockTaskMapper;
@Override
public Integer getNotEndTaskByClockId(Integer clockId) {
return clockTaskMapper.getNotEndTaskByClockId(clockId);
}
@Override
public void insert(ClockTask clockTask) {
clockTaskMapper.insert(clockTask);
}
@Override
public ClockTask getOneTaskForRunning() {
return clockTaskMapper.getOneTaskForRunning();
}
@Override
public void update(ClockTask task) {
clockTaskMapper.update(task);
}
}
4、util:上下文对象:
package com.demo.util;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 获得整个工程的上下文环境
*
*/
public final class SpringContextUtil {
/**
* 上下文
*/
private static ApplicationContext ctu;
/**
* 私有构造函数
*/
private SpringContextUtil() {
super();
}
public static void setApplicationContext(ApplicationContext applicationContext){
ctu = applicationContext;
}
/**
* 获得上下文
*
* @return ApplicationContext
*/
public static ApplicationContext getApplicationContext() {
return ctu;
}
}
5、调度器:
package com.demo.scheduler;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import org.quartz.CronScheduleBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.proxy.Factory;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import com.demo.job.ExecuteClock;
import com.demo.job.GetAddClock;
import com.demo.job.GetDeleteClock;
import com.demo.job.ExecuteTask;
import com.demo.job.GetUpdateClock;
import com.demo.module.ClockJob;
import com.demo.service.ClockJobService;
/**
* @Description:调度器
*/
@Component
public class JobScheduler {
@Autowired
private Scheduler scheduler;
@Autowired
private ClockJobService clockJobService;
//在@PostConstruct之前执行
@Bean
public Scheduler scheduler() throws SchedulerException{
SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();
return schedulerFactoryBean.getScheduler();
}
@PostConstruct
public void init() throws SchedulerException {
// 获取已被加载的job
List<ClockJob> clockJobList = clockJobService.getLoadedJobs();
for (ClockJob clockJob : clockJobList) {
addScheduleJob(clockJob);
}
// 定时(30s一次)获取未执行的Job列表加到scheduler中
JobDetail jobDetail = JobBuilder.newJob(GetAddClock.class)
.withIdentity(JobKey.jobKey("addJob")).build();
TriggerBuilder<Trigger> builder = TriggerBuilder.newTrigger()
.withIdentity(TriggerKey.triggerKey("addJob"));
builder.startAt(new Date());
Trigger trigger = builder.withSchedule(
CronScheduleBuilder.cronSchedule("0/30 0/1 * * * ? ")).build();
scheduler.scheduleJob(jobDetail, trigger);
// 定时(30s一次)获取被删除的Job列表,从scheduler中去掉
JobDetail deleteJobDetail = JobBuilder.newJob(GetDeleteClock.class)
.withIdentity(JobKey.jobKey("deleteJob")).build();
TriggerBuilder<Trigger> deleteBuilder = TriggerBuilder.newTrigger()
.withIdentity(TriggerKey.triggerKey("deleteJob"));
deleteBuilder.startAt(new Date());
Trigger deleteTrigger = deleteBuilder.withSchedule(
CronScheduleBuilder.cronSchedule("0/30 0/1 * * * ? ")).build();
scheduler.scheduleJob(deleteJobDetail, deleteTrigger);
// 定时(30s一次)获取被修改的Job列表,从scheduler中去掉
JobDetail updateJobDetail = JobBuilder.newJob(GetUpdateClock.class)
.withIdentity(JobKey.jobKey("updateJob")).build();
TriggerBuilder<Trigger> updateBuilder = TriggerBuilder.newTrigger()
.withIdentity(TriggerKey.triggerKey("updateJob"));
updateBuilder.startAt(new Date());
Trigger updateTrigger = updateBuilder.withSchedule(
CronScheduleBuilder.cronSchedule("0/30 0/1 * * * ? ")).build();
scheduler.scheduleJob(updateJobDetail, updateTrigger);
// 定时(30s一次)执行task,即真正的业务,这个时间越短越精确,越短越接近闹钟设定的频率
JobDetail taskJobDetail = JobBuilder.newJob(ExecuteTask.class)
.withIdentity(JobKey.jobKey("task")).build();
TriggerBuilder<Trigger> taskBuilder = TriggerBuilder.newTrigger()
.withIdentity(TriggerKey.triggerKey("task"));
taskBuilder.startAt(new Date());
Trigger taskTrigger = taskBuilder.withSchedule(
CronScheduleBuilder.cronSchedule("0/30 0/1 * * * ? ")).build();
scheduler.scheduleJob(taskJobDetail, taskTrigger);
// 启动
scheduler.start();
}
//新增job
public void addScheduleJob(ClockJob clockJob) throws SchedulerException {
String jobGroup = String.format("group-%s", clockJob.getClockId());
JobDetail jobDetail = JobBuilder.newJob(ExecuteClock.class)
.withIdentity(JobKey.jobKey(String.format("job-%s", clockJob.getId()), jobGroup))
.build();
JobDataMap jobDataMap = jobDetail.getJobDataMap();
jobDataMap.put("jobId", clockJob.getId());
jobDataMap.put("clockId", clockJob.getClockId());
TriggerBuilder<Trigger> builder = TriggerBuilder.newTrigger()
.withIdentity(TriggerKey.triggerKey(String.format("trigger-%s", clockJob.getId()), jobGroup));
if (new Date().before(clockJob.getStartTime())) {
builder.startAt(clockJob.getStartTime());
} else {
builder.startNow();
}
Trigger trigger = builder.withSchedule(CronScheduleBuilder.cronSchedule(clockJob.getCron())).build();
scheduler.scheduleJob(jobDetail, trigger);
System.out.println("新增job");
}
/**
* 修改job调度任务
*/
public void updateJob(ClockJob job) throws SchedulerException {
String jobGroup = String.format("group-%s", job.getClockId());
//String jobName = String.format("job-%s", job.getId());
String triggerName = String.format("trigger-%s", job.getId());
TriggerKey triggerKey = new TriggerKey(triggerName, jobGroup);
TriggerBuilder<Trigger> builder = TriggerBuilder.newTrigger()
.withIdentity(TriggerKey.triggerKey(String.format("trigger-%s", job.getId()), jobGroup));
if (new Date().before(job.getStartTime())) {
builder.startAt(job.getStartTime());
} else {
builder.startNow();
}
Trigger trigger = builder.withSchedule(CronScheduleBuilder.cronSchedule(job.getCron())).build();
scheduler.rescheduleJob(triggerKey, trigger);
System.out.println("修改job");
}
/**
* 删除job调度任务
*/
public void deleteJob(ClockJob job) throws SchedulerException {
String jobGroup = String.format("group-%s", job.getClockId());
String jobName = String.format("job-%s", job.getId());
String triggerName = String.format("trigger-%s", job.getId());
TriggerKey triggerKey = new TriggerKey(triggerName, jobGroup);
JobKey jobKey = new JobKey(jobName, jobGroup);
scheduler.pauseTrigger(triggerKey);
scheduler.unscheduleJob(triggerKey);
scheduler.deleteJob(jobKey);
System.out.println("删除job");
}
}
6、Job:
(1) 获取未加载的Job:GetAddClock
package com.demo.job;
import java.util.List;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
import org.springframework.util.CollectionUtils;
import com.demo.common.JobStatus;
import com.demo.module.ClockJob;
import com.demo.scheduler.JobScheduler;
import com.demo.service.ClockJobService;
import com.demo.util.SpringContextUtil;
/**
* @Description: 获取未加载的job
*/
public class GetAddClock implements Job{
private static ClockJobService clockJobService;
private static JobScheduler jobScheduler;
static{
clockJobService = (ClockJobService) SpringContextUtil.getApplicationContext().getBean("clockJobService");
jobScheduler = (JobScheduler) SpringContextUtil.getApplicationContext().getBean("jobScheduler");
}
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
// 获取未执行过的job
List<ClockJob> jobList = clockJobService.getUnExecutedJobs();
for (ClockJob clockJob:jobList) {
try {
jobScheduler.addScheduleJob(clockJob);
// 添加到schedule后,状态更新为已执行
clockJob.setStatus(JobStatus.EXECUTE);
clockJobService.updateFlag(clockJob);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
}
(2)获取被修改的Job:GetUpdateClock
package com.demo.job;
import java.util.List;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
import com.demo.common.JobStatus;
import com.demo.module.ClockJob;
import com.demo.scheduler.JobScheduler;
import com.demo.service.ClockJobService;
import com.demo.util.SpringContextUtil;
/**
* @Description: 获取修改的job
*/
public class GetUpdateClock implements Job{
private static ClockJobService clockJobService;
private static JobScheduler jobScheduler;
static{
clockJobService = (ClockJobService) SpringContextUtil.getApplicationContext().getBean("clockJobService");
jobScheduler = (JobScheduler) SpringContextUtil.getApplicationContext().getBean("jobScheduler");
}
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
// 获取被修改的job,修改时间
List<ClockJob> updateJobList = clockJobService.getUpdateJobs();
for (ClockJob job : updateJobList) {
try {
jobScheduler.updateJob(job);
// 去除修改标志
job.setStatus(JobStatus.EXECUTE);
clockJobService.updateFlag(job);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
}
(3):获取被删除的Job:GetDeleteClock
package com.demo.job;
import java.util.List;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
import com.demo.common.JobStatus;
import com.demo.module.ClockJob;
import com.demo.scheduler.JobScheduler;
import com.demo.service.ClockJobService;
import com.demo.util.SpringContextUtil;
/**
* @Description:获取删除的job
*/
public class GetDeleteClock implements Job{
private static ClockJobService clockJobService;
private static JobScheduler jobScheduler;
static{
clockJobService = (ClockJobService) SpringContextUtil.getApplicationContext().getBean("clockJobService");
jobScheduler = (JobScheduler) SpringContextUtil.getApplicationContext().getBean("jobScheduler");
}
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
// 获取删除的job
List<ClockJob> jobList = clockJobService.getDeleteJobs();
for (ClockJob clockJob:jobList) {
try {
jobScheduler.deleteJob(clockJob);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
}
(4)执行Job:ExecuteClock
package com.demo.job;
import java.util.List;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import com.demo.common.TaskStatus;
import com.demo.module.ClockJob;
import com.demo.module.ClockTask;
import com.demo.service.ClockJobService;
import com.demo.service.ClockTaskService;
import com.demo.util.SpringContextUtil;
/**
* @Description: 往task塞任务
*/
public class ExecuteClock implements Job{
private static ClockTaskService clockTaskService;
static{
clockTaskService = (ClockTaskService) SpringContextUtil.
getApplicationContext().getBean("clockTaskService");
}
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
Integer clockId = jobDataMap.getInt("clockId");
//先查询该clock是否有未结束的任务,即READY或RUNNING
Integer id = clockTaskService.getNotEndTaskByClockId(clockId);
if(id == null){
ClockTask clockTask = new ClockTask();
clockTask.setClockId(clockId);
clockTask.setStatus(TaskStatus.READY.toString());
clockTaskService.insert(clockTask);
}
}
}
(5)执行业务:ExecuteTask
package com.demo.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import com.demo.common.TaskStatus;
import com.demo.module.ClockTask;
import com.demo.service.ClockJobService;
import com.demo.service.ClockTaskService;
import com.demo.util.SpringContextUtil;
import com.demo.work.ClockWork;
/**
* @Description: 执行闹钟业务
*/
public class ExecuteTask implements Job{
private static ClockTaskService clockTaskService;
static{
clockTaskService = (ClockTaskService) SpringContextUtil.
getApplicationContext().getBean("clockTaskService");
}
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
ClockTask task = clockTaskService.getOneTaskForRunning();
if(task == null){
return;
}
//更新为running
task.setStatus(TaskStatus.RUNNING.toString());
clockTaskService.update(task);
System.out.println(task.getClockId()+" is running");
//执行
ClockWork.excute(task);
//更新执行结果
clockTaskService.update(task);
System.out.println(task.getClockId()+" is complated");
}
}
7、work:
package com.demo.work;
import com.demo.common.TaskStatus;
import com.demo.module.ClockTask;
/**
* @Description: TODO
*/
public class ClockWork {
public static void excute(ClockTask task) {
System.out.println("*********************我是clock"+task.getClockId());
task.setStatus(TaskStatus.SUCCESS.toString());
}
}
8、mapper:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.demo.dao.ClockJobMapper">
<resultMap id="BaseResultMap" type="com.demo.module.ClockJob">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="clock_id" jdbcType="INTEGER" property="clockId" />
<result column="cron" jdbcType="VARCHAR" property="cron" />
<result column="status" jdbcType="TINYINT" property="status" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="is_delete" jdbcType="BIT" property="isDelete" />
<result column="is_update" jdbcType="BIT" property="isUpdate" />
<result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
<result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
</resultMap>
<sql id="Base_Column_List">
id, clock_id, cron, status, create_time, is_delete, is_update, start_time, end_time
</sql>
<!--获取已经加载过的job-->
<select id="getLoadedJobs" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
FROM
t_clock_job
WHERE
status = 1
AND
is_delete = 0
AND
end_time > NOW()
</select>
<!--获取未执行的,前端新增的job-->
<select id="getUnExecutedJobs" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
FROM
t_clock_job
WHERE
status = 0
AND
is_delete = 0
AND
end_time > NOW()
</select>
<!--修改标志位-->
<update id="updateFlag" parameterType = "com.demo.module.ClockJob">
UPDATE t_clock_job set
update_time = NOW(),
is_update = 0
<if test="status != null">
,status = #{status}
</if>
WHERE id =#{id}
</update>
<!--获取删除的Job列表-->
<select id="getDeleteJobs" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
FROM
t_clock_job
WHERE
is_delete = 1
AND
end_time > NOW()
</select>
<!--获取修改的job列表-->
<select id="getUpdateJobs" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
FROM
t_clock_job
WHERE
status = 1
AND
is_delete = 0
and is_update = 1
AND
end_time > NOW()
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.demo.dao.ClockTaskMapper">
<resultMap id="BaseResultMap" type="com.demo.module.ClockTask">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="clock_id" jdbcType="INTEGER" property="clockId" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="status" jdbcType="VARCHAR" property="status" />
<result column="error_msg" jdbcType="VARCHAR" property="errorMsg" />
</resultMap>
<sql id="Base_Column_List">
id, clock_id, create_time, update_time, `status`, error_msg
</sql>
<!--查询是否有任务-->
<select id="getNotEndTaskByClockId" resultType="java.lang.Integer">
select id from t_clock_task where
clock_id = #{clockId}
and (`status` = 'READY' or `status`='RUNNING' or `status` ='WAITTING')
limit 1
</select>
<insert id="insert" parameterType="com.demo.module.ClockTask">
insert into t_clock_task (clock_id, create_time,
update_time, status, error_msg
)
values (#{clockId,jdbcType=INTEGER}, NOW(),
NOW(), #{status,jdbcType=VARCHAR}, #{errorMsg,jdbcType=VARCHAR}
)
</insert>
<select id="getOneTaskForRunning" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_clock_task
where `status` = 'READY' or `status`='WAITTING'
order by `status`,create_time,id
limit 1
</select>
<update id="update" parameterType="com.demo.module.ClockTask">
update t_clock_task
<set>
<if test="clockId != null">
clock_id = #{clockId,jdbcType=INTEGER},
</if>
update_time = NOW(),
<if test="status != null">
status = #{status,jdbcType=VARCHAR},
</if>
<if test="errorMsg != null">
error_msg = #{errorMsg,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
</mapper>
9、启动类:
package com.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import com.demo.util.SpringContextUtil;
@SpringBootApplication
@MapperScan("com.demo.dao")
public class Start {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(Start.class, args);
//实例化上下文对象
SpringContextUtil.setApplicationContext(applicationContext);
}
}
四、运行:
控制台打印:
删除第一个job:
后:
可以看出1不再执行了。
- 方法2:只需要业务本身的JOB,再新增修改业务JOB调度的增、删、改接口,如果需要修改业务JOB的调度,调用相应接口,即可实时修改过来。
import com.github.pagehelper.PageInfo;
import com.demo.job.BaseJob;
import com.demo.model.JobAndTrigger;
import com.demo.service.JobAndTriggerService;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping(value="/job")
public class JobController
{
@Autowired
private JobAndTriggerService jobAndTriggerService;
@Autowired
private Scheduler scheduler;
private static Logger log = LoggerFactory.getLogger(JobController.class);
@PostMapping(value="/addjob")
public void addjob(@RequestParam(value="jobClassName")String jobClassName,
@RequestParam(value="jobGroupName")String jobGroupName,
@RequestParam(value="cronExpression")String cronExpression) throws Exception
{
addJob(jobClassName, jobGroupName, cronExpression);
}
public void addJob(String jobClassName, String jobGroupName, String cronExpression)throws Exception{
// 启动调度器
scheduler.start();
//构建job信息
JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(jobClassName, jobGroupName).build();
//表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName)
.withSchedule(scheduleBuilder).build();
try {
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
System.out.println("创建定时任务失败"+e);
throw new Exception("创建定时任务失败");
}
}
@PostMapping(value="/pausejob")
public void pausejob(@RequestParam(value="jobClassName")String jobClassName, @RequestParam(value="jobGroupName")String jobGroupName) throws Exception
{
jobPause(jobClassName, jobGroupName);
}
public void jobPause(String jobClassName, String jobGroupName) throws Exception
{
scheduler.pauseJob(JobKey.jobKey(jobClassName, jobGroupName));
}
@PostMapping(value="/resumejob")
public void resumejob(@RequestParam(value="jobClassName")String jobClassName, @RequestParam(value="jobGroupName")String jobGroupName) throws Exception
{
jobresume(jobClassName, jobGroupName);
}
public void jobresume(String jobClassName, String jobGroupName) throws Exception
{
scheduler.resumeJob(JobKey.jobKey(jobClassName, jobGroupName));
}
@PostMapping(value="/reschedulejob")
public void rescheduleJob(@RequestParam(value="jobClassName")String jobClassName,
@RequestParam(value="jobGroupName")String jobGroupName,
@RequestParam(value="cronExpression")String cronExpression) throws Exception
{
jobreschedule(jobClassName, jobGroupName, cronExpression);
}
public void jobreschedule(String jobClassName, String jobGroupName, String cronExpression) throws Exception
{
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
} catch (SchedulerException e) {
System.out.println("更新定时任务失败"+e);
throw new Exception("更新定时任务失败");
}
}
@PostMapping(value="/deletejob")
public void deletejob(@RequestParam(value="jobClassName")String jobClassName, @RequestParam(value="jobGroupName")String jobGroupName) throws Exception
{
jobdelete(jobClassName, jobGroupName);
}
public void jobdelete(String jobClassName, String jobGroupName) throws Exception
{
scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));
scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));
scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));
}
@GetMapping(value="/queryjob")
public Map<String, Object> queryjob(@RequestParam(value="pageNum")Integer pageNum, @RequestParam(value="pageSize")Integer pageSize)
{
PageInfo<JobAndTrigger> jobAndTrigger = jobAndTriggerService.getJobAndTriggerDetails(pageNum, pageSize);
Map<String, Object> map = new HashMap<String, Object>();
map.put("JobAndTrigger", jobAndTrigger);
map.put("number", jobAndTrigger.getTotal());
return map;
}
public static BaseJob getClass(String classname) throws Exception
{
Class<?> class1 = Class.forName(classname);
return (BaseJob)class1.newInstance();
}
}