SpringBoot 集成 Quartz + MySQL

Posted VipSoft

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot 集成 Quartz + MySQL相关的知识,希望对你有一定的参考价值。

Quartz 简单使用
Java SpringBoot 中,动态执行 bean 对象中的方法

源代码地址 => https://gitee.com/VipSoft/VipBoot/tree/develop/vipsoft-quartz

工作原理解读

只要配置好 DataSource Quartz 会自动进行表的数据操作,

添加 Quartz Job 任务

保存 QRTZ_JOB_DETAILS、QRTZ_TRIGGERS => QRTZ_CRON_TRIGGERS

public void addJob(QuartzJob job) throws SchedulerException 
  ....
  JobDetail jobDetail = JobBuilder.newJob(jobClass)
                    .withIdentity(jobKey)
                    .build();
  // 放入参数,运行时的方法可以获取
  jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
  //该行代码执行后,会将定时任务插入 QRTZ_JOB_DETAILS 等相关表
  scheduler.scheduleJob(jobDetail, trigger);
  ....

//org.quartz.impl.jdbcjobstore.JobStoreSupport
public void storeJobAndTrigger(final JobDetail newJob, final OperableTrigger newTrigger) throws JobPersistenceException 
    this.executeInLock(this.isLockOnInsert() ? "TRIGGER_ACCESS" : null, new JobStoreSupport.VoidTransactionCallback() 
        public void executeVoid(Connection conn) throws JobPersistenceException 
            JobStoreSupport.this.storeJob(conn, newJob, false);  //数据保存 QRTZ_JOB_DETAILS 表
            JobStoreSupport.this.storeTrigger(conn, newTrigger, newJob, false, "WAITING", false, false); //数据保存 QRTZ_TRIGGERS 表
        
    );


public int insertTrigger(...)
 INSERT_TRIGGER
 insertExtendedTriggerProperties => INSERT_CRON_TRIGGER OR INSERT_BLOB_TRIGGER


详见:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
将 job.getJobDataMap(),对像序列化后,存入 JOB_DETAILS.JOB_DATA字段,可以是一个对像,以执行定时任务时,会把该字段反序列化,根据前期设定的内容进行业务处理

获取 Quartz Job 任务

执行计划任务时,获取 Job Detail

QuartzSchedulerThread.run()
=> qsRsrcs.getJobStore().acquireNextTriggers()
=> txCallback.execute(conn)
=> JobStoreSupport.acquireNextTriggers()
=> JobStoreSupport.retrieveJob()
=> StdJDBCDelegate.selectJobDetail()

删除 Quartz Job 任务

/**
 * <p>
 * Delete the base trigger data for a trigger.
 * </p>
 * 
 * @param conn
 *          the DB Connection
 * @return the number of rows deleted
 */
public int deleteTrigger(Connection conn, TriggerKey triggerKey) throws SQLException 
    PreparedStatement ps = null;

    deleteTriggerExtension(conn, triggerKey);
    
    try 
        ps = conn.prepareStatement(rtp(DELETE_TRIGGER));
        ps.setString(1, triggerKey.getName());
        ps.setString(2, triggerKey.getGroup());

        return ps.executeUpdate();
     finally 
        closeStatement(ps);
    

清除数据

/**
 * 清任务顺序
 */
public void clearData(Connection conn)
    throws SQLException 

    PreparedStatement ps = null;

    try 
        ps = conn.prepareStatement(rtp(DELETE_ALL_SIMPLE_TRIGGERS));
        ps.executeUpdate();
        ps.close();
        ps = conn.prepareStatement(rtp(DELETE_ALL_SIMPROP_TRIGGERS));
        ps.executeUpdate();
        ps.close();
        ps = conn.prepareStatement(rtp(DELETE_ALL_CRON_TRIGGERS));
        ps.executeUpdate();
        ps.close();
        ps = conn.prepareStatement(rtp(DELETE_ALL_BLOB_TRIGGERS));
        ps.executeUpdate();
        ps.close();
        ps = conn.prepareStatement(rtp(DELETE_ALL_TRIGGERS));
        ps.executeUpdate();
        ps.close();
        ps = conn.prepareStatement(rtp(DELETE_ALL_JOB_DETAILS));
        ps.executeUpdate();
        ps.close();
        ps = conn.prepareStatement(rtp(DELETE_ALL_CALENDARS));
        ps.executeUpdate();
        ps.close();
        ps = conn.prepareStatement(rtp(DELETE_ALL_PAUSED_TRIGGER_GRPS));
        ps.executeUpdate();
     finally 
        closeStatement(ps);
    

Demo 代码

MySQL 脚本

https://github.com/quartz-scheduler/quartz/blob/v2.3.2/quartz-core/src/main/resources/org/quartz/impl/jdbcjobstore/tables_mysql.sql

清除数据

DELETE FROM qrtz_simple_triggers ;
DELETE FROM qrtz_simprop_triggers ;
DELETE FROM qrtz_cron_triggers ;
DELETE FROM qrtz_blob_triggers ;
DELETE FROM qrtz_triggers ;
DELETE FROM qrtz_job_details ;
DELETE FROM qrtz_calendars ;
DELETE FROM qrtz_paused_trigger_grps ; 
DELETE FROM qrtz_scheduler_state ; 
DELETE FROM qrtz_locks ; 
DELETE FROM qrtz_fired_triggers

Pom.xml
如果SpringBoot版本是2.0.0以后的,则在spring-boot-starter中已经包含了quart的依赖,则可以直接使用spring-boot-starter-quartz依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!--Quartz 集成需要和数据库交互-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.0.8</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.20</version>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--hutool 工具类-->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.3.7</version>
</dependency>


QuartzJob 参考上图,建立实体

点击查看代码
package com.vipsoft.web.entity;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.io.Serializable;

/**
 * 定时任务调度
 */
public class QuartzJob implements Serializable 

    private static final long serialVersionUID = -6798153039624729495L;

    /**
     * 任务序号
     */
    private int jobId;

    /**
     * 任务名称
     */
    @NotBlank(message = "任务名称不能为空")
    @Size(max = 10, message = "任务名称不能超过10个字符")
    private String jobName;

    /**
     * 任务组名
     */
    @NotBlank(message = "任务组名不能为空")
    @Size(max = 10, message = "任务组名不能超过10个字符")
    private String jobGroup;

    /**
     * 调用目标字符串
     */
    private String invokeTarget;

    /**
     * 执行表达式
     */
    private String cronExpression;

    /**
     * cron计划策略 0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行
     */
    private String misfirePolicy = "0";

    /**
     * 并发执行 0=允许,1=禁止
     */
    private String concurrent;

    /**
     * 描述 -- 任务说明
     */
    private String description;


    /**
     * 任务状态(0正常 1暂停)
     */
    private String status;


    public int getJobId() 
        return jobId;
    

    public void setJobId(int jobId) 
        this.jobId = jobId;
    

    public String getJobName() 
        return jobName;
    

    public void setJobName(String jobName) 
        this.jobName = jobName;
    

    public String getJobGroup() 
        return jobGroup;
    

    public void setJobGroup(String jobGroup) 
        this.jobGroup = jobGroup;
    

    public String getInvokeTarget() 
        return invokeTarget;
    

    public void setInvokeTarget(String invokeTarget) 
        this.invokeTarget = invokeTarget;
    

    public String getCronExpression() 
        return cronExpression;
    

    public void setCronExpression(String cronExpression) 
        this.cronExpression = cronExpression;
    

    public String getMisfirePolicy() 
        return misfirePolicy;
    

    public void setMisfirePolicy(String misfirePolicy) 
        this.misfirePolicy = misfirePolicy;
    

    public String getConcurrent() 
        return concurrent;
    

    public void setConcurrent(String concurrent) 
        this.concurrent = concurrent;
    

    public String getStatus() 
        return status;
    

    public void setStatus(String status) 
        this.status = status;
    

    public String getDescription() 
        return description;
    

    public void setDescription(String description) 
        this.description = description;
    

核心代码:QuartzJobServiceImpl

点击查看代码
package com.vipsoft.web.service.impl;

import cn.hutool.core.util.StrUtil;
import com.vipsoft.web.config.ScheduleConstants;
import com.vipsoft.web.entity.QuartzJob;
import com.vipsoft.web.exception.CustomException;
import com.vipsoft.web.job.CommonJob;

import com.vipsoft.web.service.IQuartzJobService;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Service
public class QuartzJobServiceImpl implements IQuartzJobService 

    @Autowired
    Scheduler scheduler;


    /**
     * 新增任务
     *
     * @param job 调度信息
     * @return 结果
     */
    @Override
    public void clearAll(QuartzJob job) throws SchedulerException 
        scheduler.clear();
    
    /**
     * 新增任务
     *
     * @param job 调度信息
     * @return 结果
     */
    @Override
    public void addJob(QuartzJob job) throws SchedulerException 
        if (StrUtil.isEmpty(job.getStatus())) 
            // 如果没值,设置暂停
            job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
        
        Class<? extends Job> jobClass = CommonJob.class;
        // 构建job信息
        int jobId = job.getJobId();
        String jobName = job.getJobName();
        String jobGroup = job.getJobGroup();
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);

        JobDetail jobDetail = JobBuilder.newJob(jobClass)
                .withIdentity(jobKey)
                .build();
        // 放入参数,运行时的方法可以获取
        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);



        // 表达式调度构建器
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        cronScheduleBuilder = handleCronScheduleMisfirePolicy(job.getMisfirePolicy(), cronScheduleBuilder);

        // 按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .withSchedule(cronScheduleBuilder)
                .build();

        // 判断是否存在
        if (scheduler.checkExists(jobKey)) 
            // 防止创建时存在数据问题 先移除,然后在执行创建操作
            scheduler.deleteJob(jobKey);
        

        scheduler.scheduleJob(jobDetail, trigger);

        // 暂停任务
        if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) 
            scheduler.pauseJob(jobKey);
        
    

    /**
     * 设置定时任务策略
     */
    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(String misfirePolicy, CronScheduleBuilder cb)  
        switch (misfirePolicy) 
            case ScheduleConstants.MISFIRE_DEFAULT:
                return cb;
            case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
                return cb.withMisfireHandlingInstructionIgnoreMisfires();
            case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
                return cb.withMisfireHandlingInstructionFireAndProceed();
            case ScheduleConstants.MISFIRE_DO_NOTHING:
                return cb.withMisfireHandlingInstructionDoNothing();
            default:
                throw new CustomException(60001, "策略配置异常 " + misfirePolicy);
        
    

    /**
     * 更新任务
     *
     * @param job 调度信息
     * @return 结果
     */
    @Override
    public void updateJob(QuartzJob job) throws SchedulerException 
        // 判断是否存在
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        if (scheduler.checkExists(jobKey)) 
            // 防止创建时存在数据问题 先移除,然后在执行创建操作
            scheduler.deleteJob(jobKey);
        
        addJob(job);
    

    /**
     * 删除任务
     *
     * @param job
     * @Date 2016年1月16日
     * @since 2.0.0
     */
    @Override
    public void deleteJob(QuartzJob job) throws SchedulerException 
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        if (this.scheduler.checkExists(jobKey)) 
            this.scheduler.deleteJob(jobKey);
        
    

    /**
     * 立即运行任务
     *
     * @param job 调度信息
     * @return 结果
     */
    @Override
    public void run(QuartzJob job) throws SchedulerException 
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        scheduler.triggerJob(jobKey);
    

    /**
     * 暂停任务
     *
     * @param job 调度信息
     * @return 结果
     */
    @Override
    public void pauseJob(QuartzJob job) throws SchedulerException 
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        this.scheduler.pauseJob(jobKey);
    

    /**
     * 恢复任务
     *
     * @param job 调度信息
     * @return 结果
     */
    @Override
    public void restartJob(QuartzJob job) throws SchedulerException 
        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
        this.scheduler.resumeJob(jobKey);
    

    /**
     * 获取quartz调度器的计划任务
     *
     * @param job 调度信息
     * @return 调度任务集合
     */
    @Override
    public List<QuartzJob> listJob(QuartzJob job) throws SchedulerException 
        List<QuartzJob> scheduleJobVOList = new ArrayList<>();
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = this.scheduler.getJobKeys(matcher);
        for (JobKey jobKey : jobKeys) 
            List<? extends Trigger> triggers = this.scheduler.getTriggersOfJob(jobKey);
            for (Trigger trigger : triggers) 
                JobDetail jobDetail = this.scheduler.getJobDetail(jobKey);
                QuartzJob scheduleJobVO = (QuartzJob) jobDetail.getJobDataMap().get(ScheduleConstants.TASK_PROPERTIES);
                Trigger.TriggerState triggerState = this.scheduler.getTriggerState(trigger.getKey());
                scheduleJobVO.setStatus(triggerState.name());
                // 判断trigger
                if (trigger instanceof SimpleTrigger) 
                    SimpleTrigger simple = (SimpleTrigger) trigger;
                    scheduleJobVO.setCronExpression("重复次数:" + (simple.getRepeatCount() == -1 ? "无限" : simple.getRepeatCount()) + ",重复间隔:"
                            + (simple.getRepeatInterval() / 1000L));
                    scheduleJobVO.setDescription(simple.getDescription());
                
                if (trigger instanceof CronTrigger) 
                    CronTrigger cron = (CronTrigger) trigger;
                    scheduleJobVO.setCronExpression(cron.getCronExpression());
                    scheduleJobVO.setDescription(cron.getDescription() == null ? ("触发器:" + trigger.getKey()) : cron.getDescription());
                
                scheduleJobVOList.add(scheduleJobVO);
            
        
        return scheduleJobVOList;
    


ScheduleConfig

点击查看代码
package com.vipsoft.web.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; 
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
public class ScheduleConfig 

    /**
     * 设置属性
     */
    private Properties quartzProperties() 
        // quartz参数
        Properties prop = new Properties();
        prop.put("org.quartz.scheduler.instanceName", "VipSoftScheduler");
        prop.put("org.quartz.scheduler.instanceId", "AUTO");
        // 线程池配置
        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        prop.put("org.quartz.threadPool.threadCount", "20");
        prop.put("org.quartz.threadPool.threadPriority", "5");
        // JobStore配置
        prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
        // 集群配置
        prop.put("org.quartz.jobStore.isClustered", "true");
        prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");

        // sqlserver 启用
        // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM 0LOCKS UPDLOCK WHERE LOCK_NAME = ?");
        prop.put("org.quartz.jobStore.misfireThreshold", "12000");
        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
        return prop;
    


    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) 
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);

//        //获取配置属性--通过加载配置文件的方式获取配置
//        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
//        propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
//        //在quartz.properties中的属性被读取并注入后再初始化对象
//        propertiesFactoryBean.afterPropertiesSet();
//        factory.setQuartzProperties(propertiesFactoryBean.getObject());

        //用于quartz集群,加载quartz数据源配置
        factory.setQuartzProperties(this.quartzProperties());

        factory.setSchedulerName("VipSoftScheduler");
        //QuartzScheduler 延时启动,应用启动完10秒后 QuartzScheduler 再启动
        factory.setStartupDelay(10);
        // 可选,QuartzScheduler
        // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
        factory.setOverwriteExistingJobs(true);
        // 设置自动启动,默认为true
        factory.setAutoStartup(true);
        factory.setApplicationContextSchedulerContextKey("applicationContextKey");

        return factory;
    


暂停后,qrtz_triggers 表的 TRIGGER_STATE = PAUSED

运行效果
http://localhost:8088/schedule/add
http://localhost:8088/schedule/pause
http://localhost:8088/schedule/restart

"jobName":"测试","jobGroup":"DEFAULT","invokeTarget":"scheduletask.execute(\'VipSoft Quartz\')","cronExpression":"0/10 * * * * ?","misfirePolicy":2,"concurrent":1,"status":"0"

参考

实现方式参考:若依(RuoYi),他是新建了一张中间表,通过 init() 方法,利用中心中间表进行定时任务的初始化

/**
 * 项目启动时,初始化定时器 
 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
 */
@PostConstruct
public void init() throws SchedulerException, TaskException

    scheduler.clear();
    List<SysJob> jobList = jobMapper.selectJobAll();
    for (SysJob job : jobList)
    
        ScheduleUtils.createScheduleJob(scheduler, job);
    

SpringBoot2.6.3集成quartz

quartz使用

quartz启动需要数据库有很多表的支持,这些表的建表脚本可以通过如下方式找到

如何找到quartz的数据库脚本
在这里下载,需要注意的是下载2.2.3这个版本,不知道为什么高版本的反而没有。

集成Springboot

代码
yml配置

spring:
  application:
    name: demo-excel
  datasource:
    url: jdbc:mysql://rm-xxx.mysql.rds.aliyuncs.com:3306/quartz_demo?zeroDateTimeBehavior=convertToNull
    password: quartz_demo
    username: quartz_demo
    driver-class-name: com.mysql.cj.jdbc.Driver
    name: datasource1
  quartz:
    # quartz任务存储类型:jdbc或memory
    job-store-type: jdbc
    # 关闭时等待任务完成
    wait-for-jobs-to-complete-on-shutdown: true
    # 可以覆盖已有的任务
    overwrite-existing-jobs: true
    properties:
      org:
        quartz:
          scheduler:
            # 调度器实例名称
            instanceName: scheduler
            # 调度器实例ID自动生成
            instanceId: AUTO
          jobStore:
            class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            # quartz相关表前缀
            tablePrefix: QRTZ_
            useProperties: false
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            # 设置并发线程数量
            threadCount: 10
            # 指定线程优先级
            threadPriority: 5
            threadsInheritContextClassLoaderOfInitializingThread: true
server:
  port: 8190
mybatis-plus:
  mapper-locations: classpath*:/mapperxml/*.xml

实现一个最简单的任务,该任务输出1111

@Component
public class TestJob extends QuartzJobBean 

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext)
            throws JobExecutionException 
        // 任务的具体逻辑
        System.out.println(1111);
    

配置这个任务的执行计划

@Configuration
public class QuartzConfig 

    @Bean
    public JobDetail jobDetail() 
        JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
                .withIdentity("test", "test")
                .storeDurably()
                .build();
        return jobDetail;
    

    @Bean
    public Trigger trigger() 
        Trigger trigger = TriggerBuilder.newTrigger()
                .forJob(jobDetail())
                .withIdentity("test", "test")
                .startNow()
                .withSchedule(CronScheduleBuilder.cronSchedule("* * * * * ?"))
                .build();
        return trigger;
    

启动任务会看到控制台每秒钟打印一次1111

进阶

上诉任务是配置在代码中,执行策略为每秒钟打印一次,试想一个场景,我们这个任务的执行策略随时会变化,不可能每次一变化就去改代码。那么有没有办法把任务配置数据库中呢,再进一步,我们能不能做一个定时任务的维护页面,可以对定时任务的执行策略修改,同时可以通过页面删除定时任务,新增定时任务应该怎么做呢?

先定义一张存储定时任务的表

-- auto-generated definition
create table sys_job
(
    id              bigint                  not null primary key,
    job_name        varchar(64)             not null comment '任务名称',
    job_group       varchar(64)             not null comment '任务组名',
    method_name     varchar(500)            null comment '任务方法',
    method_params   varchar(50)             null comment '方法参数',
    cron_expression varchar(255)            null comment 'cron执行表达式',
    misfire_policy  varchar(20) default '3' null comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
    concurrent      char        default '1' null comment '是否并发执行(0允许 1禁止)',
    status          char        default '0' null comment '状态(0正常 1暂停)',
    create_by       varchar(64)             null comment '创建者',
    create_time     datetime                null comment '创建时间',
    update_by       varchar(64)             null comment '更新者',
    update_time     datetime                null comment '更新时间',
    remark          varchar(500)            null comment '备注信息'
)
    comment '定时任务调度表';

插入一条数据

INSERT INTO quartz_demo.sys_job (id, job_name, job_group, method_name, method_params, cron_expression, misfire_policy, concurrent, status, create_by, create_time, update_by, update_time, remark) VALUES (1, 'testJob2', 'test2', 'exec', null, '* * * * * ?', '2', '1', '0', null, null, null, null, null);

同时定义一张执行结果记录表

-- auto-generated definition
create table sys_job_log
(
    job_log_id     int auto_increment comment '任务日志ID'
        primary key,
    job_name       varchar(64)      not null comment '任务名称',
    job_group      varchar(64)      not null comment '任务组名',
    method_name    varchar(500)     null comment '任务方法',
    method_params  varchar(50)      null comment '方法参数',
    job_message    varchar(500)     null comment '日志信息',
    status         char default '0' null comment '执行状态(0正常 1失败)',
    exception_info varchar(2000)    null comment '异常信息',
    create_time    datetime         null comment '创建时间'
)
    comment '定时任务调度日志表';

项目启动时读取这张表里的数据放到quartz中执行
由于代码太多了,这边就不列出来代码了,demo已经上传到GitHub,项目基于springboot、mybatisplus。启动加载任务的代码在com.bxoon.service.impl.SysJobServiceImpl

以上是关于SpringBoot 集成 Quartz + MySQL的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot 2.1.1.RELEASE 集成quartz

SpringBoot2.6.3集成quartz

SpringBoot2.6.3集成quartz

SpringBoot集成Quartz动态定时任务

SpringBoot2.6.3集成quartz

springboot集成quartz实现任务调度