Bootstrap

quartz(二)动态定时器

动态更新(新增、修改、删除)定时,即新增一个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 &gt; 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 &gt; 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 &gt; 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 &gt; 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();
	}
	
	
}

 

 

;