精彩回顾
我们在spring boot quartz定时任务基本使用及介绍和spring boot quartz持久化存储分别对quartz基本信息及持久化存储进行了介绍。
这篇文章我们继续介绍给予持久化存储实现任务的动态管理。
创建表结构
为了存储我们自己动态创建的任务,除了spring boot quartz持久化存储
介绍的添加quartz表结构之外,我们还需要添加一个自己的表。以下是MySQL的表结构,其他类型的数据库请按需修改。
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 80021
Source Host : localhost:3306
Source Schema : quartz
Target Server Type : MySQL
Target Server Version : 80021
File Encoding : 65001
Date: 30/09/2020 13:34:24
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for task_quartz
-- ----------------------------
DROP TABLE IF EXISTS `task_quartz`;
CREATE TABLE `task_quartz` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`job_group` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务分组',
`job_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务名',
`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '任务描述',
`cron_expression` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'cron表达式',
`job_class_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务执行时调用哪个类的方法 包名+类名',
`job_status` varchar(5) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '1' COMMENT '任务状态',
`create_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '创建者',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`modify_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '更新者',
`modify_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `NameWithGroup`(`job_group`, `job_name`) USING BTREE COMMENT '任务及分组唯一'
) ENGINE = MyISAM AUTO_INCREMENT = 68 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
创建工程,添加依赖
如果要实现任务的动态管理,这里单独借助一张表,存储任务的信息。
先介绍一个依赖的情况:
- MySQL数据库
- mybatis执行sql
- quartz依赖
lombok
具体项目依赖如下:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
修改配置文件
application.yaml
server: port: 8080 spring: profiles: active: dev
application-dev.yaml
spring: datasource: url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&&serverTimezone=UTC username: root password: root type: com.zaxxer.hikari.HikariDataSource quartz: job-store-type: jdbc mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: net.xiangcaowuyu.quartztask.entity configuration: map-underscore-to-camel-case: true
主要配置信息:
- MySQL数据库连接
- mybatis配置
job-store-type
存储到数据库
增加mybatis相关操作
TaskQuartzMapper.xml
<?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="net.xiangcaowuyu.quartztask.mapper.TaskQuartzMapper">
<resultMap id="BaseResultMap" type="net.xiangcaowuyu.quartztask.entity.TaskQuartz">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="job_group" jdbcType="VARCHAR" property="jobGroup"/>
<result column="job_name" jdbcType="VARCHAR" property="jobName"/>
<result column="description" jdbcType="VARCHAR" property="description"/>
<result column="cron_expression" jdbcType="VARCHAR" property="cronExpression"/>
<result column="job_class_name" jdbcType="VARCHAR" property="jobClassName"/>
<result column="job_status" jdbcType="VARCHAR" property="jobStatus"/>
<result column="create_by" jdbcType="VARCHAR" property="createBy"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="modify_by" jdbcType="VARCHAR" property="modifyBy"/>
<result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
</resultMap>
<sql id="Base_Column_List">
id, job_group, job_name, description, cron_expression, job_class_name, job_status,
create_by, create_time, modify_by, modify_time
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from task_quartz
where id = #{id,jdbcType=BIGINT}
</select>
<select id="selectByJobNameAndJobGroup" resultType="net.xiangcaowuyu.quartztask.entity.TaskQuartz">
select
<include refid="Base_Column_List"/>
from task_quartz
where job_name = #{jonName,jdbcType=VARCHAR} and job_group = #{jobGroup,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
delete from task_quartz
where id = #{id,jdbcType=BIGINT}
</delete>
<delete id="deleteByJobNameAndJobGroup">
delete from task_quartz
where job_name = #{jonName,jdbcType=VARCHAR} and job_group = #{jobGroup,jdbcType=VARCHAR}
</delete>
<insert id="insert" keyColumn="id" keyProperty="id" parameterType="net.xiangcaowuyu.quartztask.entity.TaskQuartz"
useGeneratedKeys="true">
insert into task_quartz (job_group, job_name, description,
cron_expression, job_class_name, job_status,
create_by, create_time, modify_by,
modify_time)
values (#{jobGroup,jdbcType=VARCHAR}, #{jobName,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR},
#{cronExpression,jdbcType=VARCHAR}, #{jobClassName,jdbcType=VARCHAR}, #{jobStatus,jdbcType=VARCHAR},
#{createBy,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{modifyBy,jdbcType=VARCHAR},
#{modifyTime,jdbcType=TIMESTAMP})
</insert>
<insert id="insertSelective" keyColumn="id" keyProperty="id"
parameterType="net.xiangcaowuyu.quartztask.entity.TaskQuartz" useGeneratedKeys="true">
insert into task_quartz
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="jobGroup != null">
job_group,
</if>
<if test="jobName != null">
job_name,
</if>
<if test="description != null">
description,
</if>
<if test="cronExpression != null">
cron_expression,
</if>
<if test="jobClassName != null">
job_class_name,
</if>
<if test="jobStatus != null">
job_status,
</if>
<if test="createBy != null">
create_by,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="modifyBy != null">
modify_by,
</if>
<if test="modifyTime != null">
modify_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="jobGroup != null">
#{jobGroup,jdbcType=VARCHAR},
</if>
<if test="jobName != null">
#{jobName,jdbcType=VARCHAR},
</if>
<if test="description != null">
#{description,jdbcType=VARCHAR},
</if>
<if test="cronExpression != null">
#{cronExpression,jdbcType=VARCHAR},
</if>
<if test="jobClassName != null">
#{jobClassName,jdbcType=VARCHAR},
</if>
<if test="jobStatus != null">
#{jobStatus,jdbcType=VARCHAR},
</if>
<if test="createBy != null">
#{createBy,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=TIMESTAMP},
</if>
<if test="modifyBy != null">
#{modifyBy,jdbcType=VARCHAR},
</if>
<if test="modifyTime != null">
#{modifyTime,jdbcType=TIMESTAMP},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="net.xiangcaowuyu.quartztask.entity.TaskQuartz">
update task_quartz
<set>
<if test="jobGroup != null">
job_group = #{jobGroup,jdbcType=VARCHAR},
</if>
<if test="jobName != null">
job_name = #{jobName,jdbcType=VARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=VARCHAR},
</if>
<if test="cronExpression != null">
cron_expression = #{cronExpression,jdbcType=VARCHAR},
</if>
<if test="jobClassName != null">
job_class_name = #{jobClassName,jdbcType=VARCHAR},
</if>
<if test="jobStatus != null">
job_status = #{jobStatus,jdbcType=VARCHAR},
</if>
<if test="createBy != null">
create_by = #{createBy,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=TIMESTAMP},
</if>
<if test="modifyBy != null">
modify_by = #{modifyBy,jdbcType=VARCHAR},
</if>
<if test="modifyTime != null">
modify_time = #{modifyTime,jdbcType=TIMESTAMP},
</if>
</set>
where id = #{id,jdbcType=BIGINT}
</update>
<update id="updateByPrimaryKey" parameterType="net.xiangcaowuyu.quartztask.entity.TaskQuartz">
update task_quartz
set job_group = #{jobGroup,jdbcType=VARCHAR},
job_name = #{jobName,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
cron_expression = #{cronExpression,jdbcType=VARCHAR},
job_class_name = #{jobClassName,jdbcType=VARCHAR},
job_status = #{jobStatus,jdbcType=VARCHAR},
create_by = #{createBy,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=TIMESTAMP},
modify_by = #{modifyBy,jdbcType=VARCHAR},
modify_time = #{modifyTime,jdbcType=TIMESTAMP}
where id = #{id,jdbcType=BIGINT}
</update>
</mapper>
TaskQuartz.java
/**
* @author laughing
* @date 2020/9/30
* @site https://www.lisen.org
*/
@Data
public class TaskQuartz implements Serializable {
private Long id;
/**
* 任务分组
*/
private String jobGroup;
/**
* 任务名
*/
private String jobName;
/**
* 任务描述
*/
private String description;
/**
* cron表达式
*/
private String cronExpression;
/**
* 任务执行时调用哪个类的方法 包名+类名
*/
private String jobClassName;
/**
* 任务状态
*/
private String jobStatus;
/**
* 创建者
*/
private String createBy;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新者
*/
private String modifyBy;
/**
* 更新时间
*/
private Date modifyTime;
private static final long serialVersionUID = 1L;
}
TaskQuartzService.java
/**
* @author laughing
* @date 2020/9/30
* @site https://www.lisen.org
*/
public interface TaskQuartzService {
/**
* 根据主键删除
* @param id 主键
* @return 删除行数
*/
int deleteByPrimaryKey(Long id);
/**
* 插入
* @param record 实体
* @return 成功返回1
*/
int insert(TaskQuartz record);
/**
* 插入修改的值
* @param record 实体
* @return 成功返回1
*/
int insertSelective(TaskQuartz record);
/**
* 根据主键获取
* @param id 主键
* @return 实体
*/
TaskQuartz selectByPrimaryKey(Long id);
/**
* 更新
* @param record 实体
* @return 更新成功返回1
*/
int updateByPrimaryKeySelective(TaskQuartz record);
/**
* 更新所有值
* @param record 实体
* @return 成功返回1
*/
int updateByPrimaryKey(TaskQuartz record);
/**
* 根据名称及分组查找
* @param jobName 任务名称
* @param jobGroup 任务分组
* @return 任务
*/
TaskQuartz selectByJobNameAndJobGroup(@Param("jonName") String jobName, @Param("jobGroup") String jobGroup);
/**
* 根据名称及分组查找
* @param jobName 任务名称
* @param jobGroup 任务分组
* @return 任务
*/
int deleteByJobNameAndJobGroup(@Param("jonName") String jobName,@Param("jobGroup") String jobGroup);
}
TaskQuartzServiceImpl.java
/**
* @author laughing
* @date 2020/9/30
* @site https://www.lisen.org
*/
@Service
public class TaskQuartzServiceImpl implements TaskQuartzService {
@Resource
TaskQuartzMapper taskQuartzMapper;
/**
* 根据主键删除
*
* @param id 主键
* @return 删除行数
*/
@Override
public int deleteByPrimaryKey(Long id) {
return taskQuartzMapper.deleteByPrimaryKey(id);
}
/**
* 插入
*
* @param record 实体
* @return 成功返回1
*/
@Override
public int insert(TaskQuartz record) {
return taskQuartzMapper.insert(record);
}
/**
* 插入修改的值
*
* @param record 实体
* @return 成功返回1
*/
@Override
public int insertSelective(TaskQuartz record) {
return taskQuartzMapper.insertSelective(record);
}
/**
* 根据主键获取
*
* @param id 主键
* @return 实体
*/
@Override
public TaskQuartz selectByPrimaryKey(Long id) {
return taskQuartzMapper.selectByPrimaryKey(id);
}
/**
* 更新
*
* @param record 实体
* @return 更新成功返回1
*/
@Override
public int updateByPrimaryKeySelective(TaskQuartz record) {
return taskQuartzMapper.updateByPrimaryKeySelective(record);
}
/**
* 更新所有值
*
* @param record 实体
* @return 成功返回1
*/
@Override
public int updateByPrimaryKey(TaskQuartz record) {
return taskQuartzMapper.updateByPrimaryKey(record);
}
/**
* 根据名称及分组查找
*
* @param jobName 任务名称
* @param jobGroup 任务分组
* @return 任务
*/
@Override
public TaskQuartz selectByJobNameAndJobGroup(String jobName, String jobGroup) {
return taskQuartzMapper.selectByJobNameAndJobGroup(jobName,jobGroup);
}
/**
* 根据名称及分组查找
*
* @param jobName 任务名称
* @param jobGroup 任务分组
* @return 任务
*/
@Override
public int deleteByJobNameAndJobGroup(String jobName, String jobGroup) {
return taskQuartzMapper.deleteByJobNameAndJobGroup(jobName,jobGroup);
}
}
增加测试任务
PrintJob.java
/**
* @author laughing
* @date 2020/9/30
* @site https://www.lisen.org
*/
public class PrintJob implements Job {
private final Logger logger = LoggerFactory.getLogger(PrintJob.class);
/**
* 执行任务
*
* @param jobExecutionContext
* @throws JobExecutionException
*/
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try {
logger.info("Hello Job执行时间: " + new Date() + " Blog:" + jobExecutionContext.getJobDetail().getJobDataMap().get("blog"));
Thread.sleep(1000 * 5);
System.out.println("================执行完成========================");
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试新增任务
新增任务时,我们并没有创建quartz相关表,只是存储到task_quartz表中,任务启动时,插入quartz表
/**
* 新增或者保存任务
* 任务只是存储到task_quartz表中,任务启动时,插入quartz表
*
* @param taskQuartz 实体
* @return 结果
*/
@RequestMapping("saveQuartz")
public Result save(@RequestBody TaskQuartz taskQuartz) {
TaskQuartz task = taskQuartzService.selectByJobNameAndJobGroup(taskQuartz.getJobName(), taskQuartz.getJobGroup());
if (task == null) {
task = new TaskQuartz();
BeanUtils.copyProperties(taskQuartz, task);
taskQuartzService.insertSelective(task);
} else {
taskQuartzService.updateByPrimaryKeySelective(taskQuartz);
}
return Result.ok();
}
测试启动任务
任务启动时,启动任务时,将任务信息持久化到quartz表中
/**
* 启用任务
* 启动任务时,将任务信息持久化到quartz表中
*
* @param taskQuartz 实体
* @return 结果
*/
@RequestMapping("startJob")
public Result startJob(@RequestBody TaskQuartz taskQuartz) {
try {
JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz);
// 存在先删除
if (scheduler.checkExists(jobKey)) {
scheduler.deleteJob(jobKey);
}
Class classz = Class.forName(taskQuartz.getJobClassName());
JobDetail jobDetail = JobBuilder.newJob()
.withDescription(taskQuartz.getDescription())
.withIdentity(jobKey)
.usingJobData("blog", "https://www.xiangcaowuyu.net")
.ofType(classz).build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("Trigger_" + taskQuartz.getJobName(), "TriggerGroup_" + taskQuartz.getJobGroup())
.withSchedule(CronScheduleBuilder.cronSchedule(taskQuartz.getCronExpression()))
.startNow()
.build();
scheduler.scheduleJob(jobDetail, trigger);
} catch (Exception exception) {
return Result.error(exception.getMessage());
}
return Result.ok();
}
通过postman测试,我们可以观察控制台,任务时10s执行一次
暂停任务
/**
* 暂停任务
*
* @param taskQuartz 实体
* @return 结果
*/
@RequestMapping("shutdown")
public Result shutdown(@RequestBody TaskQuartz taskQuartz) {
try {
JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz);
scheduler.pauseJob(jobKey);
return Result.ok();
} catch (Exception ex) {
return Result.error(ex.getMessage());
}
}
恢复任务
/**
* 恢复任务
*
* @param taskQuartz 实体
* @return 结果
*/
@RequestMapping("resumeJob")
public Result resumeJob(@RequestBody TaskQuartz taskQuartz) {
try {
JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz);
scheduler.resumeJob(jobKey);
return Result.ok();
} catch (Exception ex) {
return Result.error(ex.getMessage());
}
}
删除任务
/**
* 删除任务
*
* @param taskQuartz 实体
* @return 结果
*/
@RequestMapping("removeJob")
public Result removeJob(@RequestBody TaskQuartz taskQuartz) {
try {
JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz);
scheduler.deleteJob(jobKey);
taskQuartzService.deleteByJobNameAndJobGroup(taskQuartz.getJobName(),taskQuartz.getJobGroup());
return Result.ok();
} catch (Exception ex) {
return Result.error(ex.getMessage());
}
}
现在可以了哦