spring boot Quartz基于持久化存储的动态管理

spring boot Quartz基于持久化存储的动态管理

Laughing
2020-09-30 / 0 评论 / 1,113 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2024年03月21日,已超过303天没有更新,若内容或图片失效,请留言反馈。

精彩回顾

我们在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;

创建工程,添加依赖

如果要实现任务的动态管理,这里单独借助一张表,存储任务的信息。

先介绍一个依赖的情况:

  1. MySQL数据库
  2. mybatis执行sql
  3. quartz依赖
  4. 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
    

    主要配置信息:

  5. MySQL数据库连接
  6. mybatis配置
  7. 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());
        }
    }
0

评论 (0)

取消
  1. 头像
    Laughing 作者
    iPhone · Safari
    @ 不错的主题

    现在可以了哦

    回复
  2. 头像
    Laughing 作者
    Windows 10 · Google Chrome

    画图

    回复