Quartz定时任务框架(一)

1. 什么是Quartz

Quartz 是一个完全由 Java 编写的开源作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制。

Quartz 可以与 J2EE 与 J2SE 应用程序相结合也可以单独使用。

Quartz 允许程序开发人员根据时间的间隔来调度作业。

Quartz 实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。

2. 背景

拿火车票购票来说,当你下单后,后台就会插入一条待支付的task(job),一般是30分钟,超过30min后就会执行这个job,去判断你是否支付,未支付就会取消此次订单;当你支付完成之后,后台拿到支付回调后就会再插入一条待消费的task(job),Job触发日期为火车票上的出发日期,超过这个时间就会执行这个job,判断是否使用等。

在实际项目中,当Job过多,肯定不能人工操作,这时候就需要任务调度框架来帮我们自动执行这些程序,那该如何去实现?

  • 首先我们需要定义实现一个定时功能的接口,称为Task(Job),如定时发送邮件的task(Job),重启机器的task(Job),实现接口如下图:
    Quartz定时任务框架(一)_第1张图片
  • 有了任务,还需要一个能够实现出发任务去执行的触发器Trigger,Trigger最基本功能是执行task(Job)的执行时间,执行间隔,执行次数等
    Quartz定时任务框架(一)_第2张图片
  • 有了Job和Trigger后,如何将两者结合,并指定Trigger执行指定Job呢? 这个时候就有了调度器Schedule.
    Quartz定时任务框架(一)_第3张图片
    所以,Quartz的基本组成部分:
  • 调度器: Scheduler
  • 任务: JobDetail
  • 触发器: Tigger, 包括SimpleTirgger和CronTrigger

3. Quartz快速入门

3.1 入门Demo

3.1.1 导入依赖



    org.quartz-scheduler
    quartz
    2.3.2

3.1.2 新建Job

package cn.com.mochasoft.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.time.LocalDate;
import java.util.Random;

/**
 * 定时任务入门案例
 * 创建Job,定时输出当前时间
 * @author: zhouxb
 *
 * */
public class PrintWordsJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println(jobExecutionContext.getJobDetail().getJobDataMap().get("jobDetail"));
        System.out.println(jobExecutionContext.getTrigger().getJobDataMap().get("trigger1"));
        String printTime = LocalDate.now().toString();
        System.out.println("PrintWordsJob start at : " + printTime + ", prints: Hello Job-" + new Random().nextInt(100));
    }
}

3.1.3 新建Scheduler

package cn.com.mochasoft.schedule;

import cn.com.mochasoft.job.PrintWordsJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Collection;
import java.util.concurrent.TimeUnit;

/**
 * 定时任务调度器
 *
 * @author zhouxiaobing
 */
public class MyScheduler {
    public static void main(String[] args) throws SchedulerException, InterruptedException {
        //创建调度器Scheduler
        StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

        //创建JobDetail实例,并与printWordsJob类绑定()
        JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class)
                .withIdentity("jobDetail", "group")
                .usingJobData("jobDetail", "这是MyScheduler的jobDetail")
                .build();

        //构建Trigger实例,每隔1s执行一次
        SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger", "triggerGroup")
                .usingJobData("trigger", "这是jobDetail的trigger")
                .startNow() //立即生效
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(30) //每隔30s执行一次
                        .repeatForever()) //一直执行
                .build();

        //执行
        scheduler.scheduleJob(jobDetail, trigger);
        System.out.println("-----------------------scheduler start ! ------------------------");
        scheduler.start();

        //睡眠
        TimeUnit.MINUTES.sleep(1);
        scheduler.shutdown();
        System.out.println("-----------------------scheduler shutdown ! ------------------------");
    }
}

3.1.4 控制台输出结果

Quartz定时任务框架(一)_第4张图片

4. 核心解析

  • Job和JobDetail
  • JobExecutionContext
  • JobDataMap
  • Trigger
  • Schedule

4.1 Job和JobDetail

Job是Quartz的一个接口,接口中只有一个execute方法,用于编辑具体任务逻辑

JobDetail绑定Job,并为Job提供属性:

  • name
  • group
  • jobClass
  • jobDataMap

由于任务有可能存在并发执行的情况,如果Scheduler直接调用Job, 就会存在对同一个Job实例并发访问的问题, 使用JobDetail & Job的方式, Scheduler每次执行, 都会根据JobDetail创建一个新的Job实例,规避了并发访问的问题.

4.2 JobExecutionContext

JobExecutionContext中包含了Quartz运行时的环境以及Job本身的详细数据信息.
当Scheduler调度执行一个Job, 就会将JobExecutionContext传递给该Job的execute()中, Job可以通过JobExecutionContext对象获取信息, 主要信息有:
Quartz定时任务框架(一)_第5张图片

4.3 JobDataMap

JobDataMap实现了JDK的Map接口, 可以以K-V形式存储数据. JobDetail, Trigger都可以使用JobDataMap来设置一些参数或信息
Quartz定时任务框架(一)_第6张图片

在Job执行execute()方法的时候, JobExecutionContext可以获取这些信息
在这里插入图片描述
控制台输出结果:
Quartz定时任务框架(一)_第7张图片

4.4 Trigger

Trigger是Quartz触发器, 会去通知Scheduler何时执行对应Job, 采用的是builder模式,常用方法:

  • withIdentity(): 给触发器设置名称/组名
  • startNow(): 立刻启动
  • withSchedule(ScheduleBuilder scheduleBuilder): 以某种触发器触发(重点内容)
  • usingJobData(String dataKey, Boolean value): 给具体job传递参数
    例如:
Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)
                .repeatForever()).build();

4.4.1 withSchedule

查看SchedulerBuilder, 这个是抽象类,其共有4中具体实现方法, 如图:
Quartz定时任务框架(一)_第8张图片

  • SimpleScheduleBuilder
    最简单的触发器,表示从某一时刻开始,以一定时间间隔执行任务
    方法:
    • repeatInterval: 重复间隔
    • repeatCount: 重复次数
      比如: 现在开始,以后每隔一小时执行一次
Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInHours(1)
                .repeatForever()).build();
  • DailyTimeIntervalSchedulebuilder
    表示每一天的某个时间段, 以一定的时间间隔执行任务, 可以指定具体的某一天(星期一/星期二/星期三)
    方法:
    - intervalUnit 重复间隔(秒/分钟/小时)
    - daysOfWeek 具体的星期.(默认周一到周日)
    - startTimeOfDay 每天开始时间, 默认 0.0
    - endTimeOfDay 每天结束时间, 默认23:59:59
    - repeatCount 重复次数. 默认-1 不限次数
    - interval 每次执行间隔
    比如每周一到周四早上9点开始,晚上16点结束,每次执行间隔1 小时.
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
                //加入 scheduler之后立刻执行
                .startNow()
                //定时 ,每个1秒钟执行一次
                .withSchedule(dailyTimeIntervalSchedule()
                        .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0)) //第天9:00开始
                        .endingDailyAt(TimeOfDay.hourAndMinuteOfDay(16, 0)) //16:00 结束
                        .onDaysOfTheWeek(MONDAY,TUESDAY,WEDNESDAY,THURSDAY) //周一至周五执行
                        .withIntervalInHours(1) //每间隔1小时执行一次
                        ).build();
  • CalendarIntervalScheduleBuilder
    和SimpleScheduleBuilder类似,都是表示从某一时刻开始,以一定时间间隔执行任务。但是SimpleScheduleBuilder无法指定一些特殊情况,比如每个月执行一次,每周执行一次、每一年执行一次
    方法:
    - interval 执行间隔
    - intervalUnit 执行间隔单位(秒/分钟/小时/日/月/星期/年)
  Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
                //加入 scheduler之后立刻执行
                .startNow()
                //定时 ,每个1秒钟执行一次
                .withSchedule(calendarIntervalSchedule()
                        .withIntervalInWeeks(1) //每周执行一次
                        ).build();
  • CronScheduleBuilder(重点)
    最自由的方式, 重点是其中的cron表达式
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
                //加入 scheduler之后立刻执行
                .startNow()
                //定时 ,每个1秒钟执行一次
                .withSchedule(cronSchedule("0 0/2 8-17 * * ?") // 每天8:00-17:00,每隔2分钟执行一次
                        ).build();

推荐网站:在线生成Cron

4.5 Scheduler

Scheduler是Quartz核心所在,所有任务都是通过Scheduler调度开始.
Scheduler是一个接口类, 所有具体实现类都是通过SchedulerFactory工厂类实现, 但是Schedulerfactory
有两个具体实现类, 如图:
Quartz定时任务框架(一)_第9张图片

  1. StdSchedulerFactory: 默认值加载为当前工作目录下的"quartz.properties"属性文件. 如果加载失败, 会加载org/quartz包下的"quartz.properties"属性文件.
  2. DirectSchedulerfactory: 这个是为那些想绝对控制Scheduler实例而使用,没用过QAQ

4.6 如何禁止并发执行

项目中出现了一种情况,本来job执行时间只需要10s,但是由于数据库量增大之后,执行时间变成了60s,而我设置的间隔时间是30s,这样就会出现上次任务还没执行完成,下次任务就开始执行了。所以,在这种情况下,我们要禁止quart的并发操作.
3. Spring中将job的concurrent属性设为false, 默认为true

 
        
        
        
 

5. Quartz进阶(一)

5.1 实现Springboot整合Quartz

spring官网有具体的配置文档,实现quartz与springboot整合

5.1.1 spring.io官网查看文档

Quartz定时任务框架(一)_第10张图片
查看spring boot features
Quartz定时任务框架(一)_第11张图片
Quartz定时任务框架(一)_第12张图片
Spring Boot为使用Quartz调度器提供了多种方便,包括"Spring-Boot-Starter-Quartz"依赖。如果Quartz可用,则调度器通过SchedulerFactoryBean自动配置。

5.1.2 添加Spring-Boot-Starter-Quartz依赖

		
			org.springframework.boot
			spring-boot-starter-quartz
		

5.1.3 创建Job

按照文档提供的案例,Job需要继承QuartzJobBean
Quartz定时任务框架(一)_第13张图片

package com.mochasoft.job;

import com.mochasoft.service.HelloSpringService;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.time.LocalTime;
import java.util.StringJoiner;

public class SpringBootJob1 extends QuartzJobBean { // 继承QuartzJobBean
    // 实现业务层自动注入
    @Autowired
    private HelloSpringService helloSpringService;

    // 执行代码块
    @Override
    protected void executeInternal(final JobExecutionContext jobExecutionContext) throws JobExecutionException {

        final StringJoiner outStr = new StringJoiner("|") // 分隔符
                .add("SpringBootJob1.executeInternal")
                .add("nowDateTime: " + LocalTime.now())
                .add(helloSpringService.HelloSpring());
        System.out.println(outStr);
    }
}

HelloService代码块

package com.mochasoft.service;

import org.springframework.stereotype.Service;

@Service
public class HelloSpringService {

//    @Autowired
//    private DataSource dataSource;
    
    public String HelloSpring() {
        return "hello Spring";
    }
    
//
//    @PostConstruct
//    public void test() {
//        System.out.println(dataSource.toString());
//    }

}

5.1.3 实现自动注入Scheduler(一)

package com.mochasoft.jobconfig;

import com.mochasoft.job.SpringBootJob1;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class JobInit {

    // springboot自动注入Scheduler调度器
    @Autowired
    private Scheduler scheduler;

    /**
     * @PostConstruct
     * 修饰非静态void()方法。该方法会在服务器家在Servlet时候运行,并且只会被服务器执行一次。
     * 该方法在构造函数之后执行,init()方法之前执行。
     * 该注解的方法在整个Bean初始化中的执行顺序:
     * Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
     * */
    @PostConstruct
    public void initJob() throws SchedulerException {
        
        // 查看当前线程数
        //System.out.println("quartz线程数为:" + scheduler.getMetaData().getThreadPoolSize());
        
        // 创建JobDetail
        JobDetail jobDetail = JobBuilder.newJob(SpringBootJob1.class)
                .build();
        
        // 创建Trigger
        Trigger trigger = TriggerBuilder.newTrigger()
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(10)) // 每隔10s执行一次,一直执行下去
                .startNow() // 立即开始
                .build();
        
        // 调度器执行
        scheduler.scheduleJob(jobDetail, trigger);
    }
}

启动SpringBoot,查看运行结果
Quartz定时任务框架(一)_第14张图片

5.1.4 实现自动注入Scheduler(二)

package com.mochasoft.jobconfig;

import com.mochasoft.job.SpringBootJob1;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration //声明该类为配置类,交给Spring管理
public class JobConfig {
    
    // 自动注入Scheduler
    @Autowired
    private Scheduler scheduler;

//    @Bean
//    @QuartzDataSource
//    public DataSource dataSource() {
//        DriverManagerDataSource dataSource = new DriverManagerDataSource();
//        dataSource.setUsername("zhouxb");
//        dataSource.setPassword("zzzz");
//        return dataSource;
//    }

    // 创建JobDetail,并交给Spring管理
    @Bean
    public JobDetail jobDetail(){
        return JobBuilder.newJob(SpringBootJob1.class)
                .withIdentity("jobDetail") //标识身份
                .storeDurably() // 持久化jobDetail
                .build();
    }

    // 创建Trigger,并交给Spring管理
    @Bean
    public Trigger trigger() {
        return TriggerBuilder.newTrigger()
                .forJob("jobDetail") // 执行指定JobDetail
                .startNow()
                .build();
    }

}

运行springboot,查看控制台输出结果:
Quartz定时任务框架(一)_第15张图片

5.1.5 总结

实现Springboot自动注入Scheduler方法有两个:

  • 通过手动创建JobDetail和Trigger方式实现(推荐
  • 通过配置类+Bean注解的方式实现(需要注意Bean的名称,如果Bean过多容易混淆)

6. SpringBoot整合Quartz(持久化到数据库)

6.1 背景

最近在做项目,项目中有个需求:需要使用定时任务,这个定时任务需要即时生效。
查看Quartz官网之后发现:Quartz提供两种基本作业存储类型:

  1. RAMJobStore :RAM也就是内存,默认情况下Quartz会将任务调度存在内存中,这种方式性能是最好的,因为内存的速度是最快的。不好的地方就是数据缺乏持久性,但程序崩溃或者重新发布的时候,所有运行信息都会丢失
  2. JDBC作业存储:存到数据库之后,可以做单点也可以做集群,当任务多了之后,可以统一进行管理。关闭或者重启服务器,运行的信息都不会丢失。缺点就是运行速度快慢取决于连接数据库的快慢。
    所以决定采用 JDBC作业存储的方式。

6.1 为什么要持久化

  1. 方便以后可以做集群
  2. 任务可以进行管理, 随时停止, 暂停, 修改

6.2 Quartz初始化表

如果需要做持久化的话,数据肯定是要存在数据库的,那么到底存在哪些表呢?

## 说明 下面的所有表都要创建 要不然会出现错误 在mysql的命令行执行即可
## 保存job详细信息的表
1.qrtz_blob_triggers : 以Blob 类型存储的触发器。
2.qrtz_calendars:存放日历信息, quartz可配置一个日历来指定一个时间范围。
3.qrtz_cron_triggers:存放cron类型的触发器。
4.qrtz_fired_triggers:存放已触发的触发器。
5.qrtz_job_details:存放一个jobDetail信息。
6.qrtz_job_listeners:job**监听器**。
7.qrtz_locks: 存储程序的悲观锁的信息(假如使用了悲观锁)。
8.qrtz_paused_trigger_graps:存放暂停掉的触发器。
9.qrtz_scheduler_state:调度器状态。
10.qrtz_simple_triggers:简单触发器的信息。
11.qrtz_triggers:触发器的基本信息。
————————————————
CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,##job的名字
JOB_GROUP VARCHAR(200) NOT NULL,##job的所属组的名字
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,##job实现类的完全包名,quartz就是根据这个路径到classpath找到该job类
IS_DURABLE VARCHAR(1) NOT NULL,#是否持久化,把该属性设置为1,quartz会把job持久化到数据库中
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,#一个blob字段,存放持久化job对象
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;

#保存trigger信息 触发器信息表
CREATE TABLE QRTZ_TRIGGERS (
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,#trigger的名字,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,#trigger所属组的名字
  JOB_NAME VARCHAR(200) NOT NULL,#qrtz_job_details表job_name的外键
  JOB_GROUP VARCHAR(200) NOT NULL,#qrtz_job_details表job_group的外键
  DESCRIPTION VARCHAR(250) NULL,
  NEXT_FIRE_TIME BIGINT(13) NULL,
  PREV_FIRE_TIME BIGINT(13) NULL,
  PRIORITY INTEGER NULL,
  TRIGGER_STATE VARCHAR(16) NOT NULL,#:当前trigger状态,设置为ACQUIRED,如果设置为WAITING,则job不会触发
  TRIGGER_TYPE VARCHAR(8) NOT NULL,#CRON
  START_TIME BIGINT(13) NOT NULL,
  END_TIME BIGINT(13) NULL,
  CALENDAR_NAME VARCHAR(200) NULL,
  MISFIRE_INSTR SMALLINT(2) NULL,
  JOB_DATA BLOB NULL,
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
  REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
  ENGINE=InnoDB;

#存储cron表达式表
CREATE TABLE QRTZ_CRON_TRIGGERS (
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,#triggers表trigger_name的外键
  TRIGGER_GROUP VARCHAR(200) NOT NULL,# qrtz_triggers表trigger_group的外键
  CRON_EXPRESSION VARCHAR(120) NOT NULL,#cron表达式
  TIME_ZONE_ID VARCHAR(80),
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
  ENGINE=InnoDB;

CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  REPEAT_COUNT BIGINT(7) NOT NULL,
  REPEAT_INTERVAL BIGINT(12) NOT NULL,
  TIMES_TRIGGERED BIGINT(10) NOT NULL,
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
  ENGINE=InnoDB;


CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  STR_PROP_1 VARCHAR(512) NULL,
  STR_PROP_2 VARCHAR(512) NULL,
  STR_PROP_3 VARCHAR(512) NULL,
  INT_PROP_1 INT NULL,
  INT_PROP_2 INT NULL,
  LONG_PROP_1 BIGINT NULL,
  LONG_PROP_2 BIGINT NULL,
  DEC_PROP_1 NUMERIC(13,4) NULL,
  DEC_PROP_2 NUMERIC(13,4) NULL,
  BOOL_PROP_1 VARCHAR(1) NULL,
  BOOL_PROP_2 VARCHAR(1) NULL,
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
  ENGINE=InnoDB;

CREATE TABLE QRTZ_BLOB_TRIGGERS (
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  BLOB_DATA BLOB NULL,
  PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
  INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
  FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
  ENGINE=InnoDB;

CREATE TABLE QRTZ_CALENDARS (
  SCHED_NAME VARCHAR(120) NOT NULL,
  CALENDAR_NAME VARCHAR(200) NOT NULL,
  CALENDAR BLOB NOT NULL,
  PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
  ENGINE=InnoDB;

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
  SCHED_NAME VARCHAR(120) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
  ENGINE=InnoDB;

CREATE TABLE QRTZ_FIRED_TRIGGERS (
  SCHED_NAME VARCHAR(120) NOT NULL,
  ENTRY_ID VARCHAR(95) NOT NULL,
  TRIGGER_NAME VARCHAR(200) NOT NULL,
  TRIGGER_GROUP VARCHAR(200) NOT NULL,
  INSTANCE_NAME VARCHAR(200) NOT NULL,
  FIRED_TIME BIGINT(13) NOT NULL,
  SCHED_TIME BIGINT(13) NOT NULL,
  PRIORITY INTEGER NOT NULL,
  STATE VARCHAR(16) NOT NULL,
  JOB_NAME VARCHAR(200) NULL,
  JOB_GROUP VARCHAR(200) NULL,
  IS_NONCONCURRENT VARCHAR(1) NULL,
  REQUESTS_RECOVERY VARCHAR(1) NULL,
  PRIMARY KEY (SCHED_NAME,ENTRY_ID))
  ENGINE=InnoDB;

CREATE TABLE QRTZ_SCHEDULER_STATE (
  SCHED_NAME VARCHAR(120) NOT NULL,
  INSTANCE_NAME VARCHAR(200) NOT NULL,
  LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
  CHECKIN_INTERVAL BIGINT(13) NOT NULL,
  PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
  ENGINE=InnoDB;

CREATE TABLE QRTZ_LOCKS (
  SCHED_NAME VARCHAR(120) NOT NULL,
  LOCK_NAME VARCHAR(40) NOT NULL,
  PRIMARY KEY (SCHED_NAME,LOCK_NAME))
  ENGINE=InnoDB;
COMMIT;

具体的job 触发器 表的数据

# 插入要执行的 job
INSERT INTO `QRTZ_JOB_DETAILS` VALUES ('scheduler', 'registerDoctorDetail', 'DEFAULT', NULL, 'com.xxx.xxx.business.quartz.jobs.RegisterRongDoctor', '1', '0', '0', '0', null);
#Trigger
INSERT INTO `QRTZ_TRIGGERS` VALUES ('scheduler', 'register_doctor', 'register_group', 'registerDoctorDetail', 'DEFAULT', NULL, 0, 0, 0, 'ACQUIRED', 'CRON', 1502208000, 0, NULL, 0, null);
#trigger express
INSERT INTO `QRTZ_CRON_TRIGGERS` VALUES ('scheduler', 'register_doctor', 'register_group', '0/30 * * * * ?', 'GMT+08');

COMMIT;

6.3 Springboot整合Quartz持久化

6.3.1 添加持久化相关依赖

			
			mysql
			mysql-connector-java
			runtime
		
		
			org.springframework.boot
			spring-boot-starter-data-jdbc
		

6.3.2 编辑application.yml文件

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1/quartzTest?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
  quartz:
    job-store-type: JDBC
    jdbc:
      initialize-schema: always

6.3.3 编辑HelloSpringService

package com.mochasoft.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import javax.annotation.PostConstruct;

@Service
public class HelloSpringService {
    //自动注入数据源
    @Autowired
    private DataSource dataSource;

    public String HelloSpring() {
        return "hello Spring";
    }

    // 查看数据源是否注入并打印
    @PostConstruct
    public void test() {
        System.out.println(dataSource.toString());
    }

}

6.3.4 编辑JobInit

注释掉JobConfig上的@Configuration注解

package com.mochasoft.jobconfig;

import com.mochasoft.job.SpringBootJob1;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class JobInit {

    // springboot自动注入Scheduler调度器
    @Autowired
    private Scheduler scheduler;

    /**
     * @PostConstruct
     * 修饰非静态void()方法。该方法会在服务器家在Servlet时候运行,并且只会被服务器执行一次。
     * 该方法在构造函数之后执行,init()方法之前执行。
     * 该注解的方法在整个Bean初始化中的执行顺序:
     * Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
     * */
    @PostConstruct
    public void initJob() throws SchedulerException {

        // 查看当前线程数
        System.out.println("quartz线程数为:" + scheduler.getMetaData().getThreadPoolSize());

        // 创建JobDetail
        JobDetail jobDetail = JobBuilder.newJob(SpringBootJob1.class)
                .build();

        // 创建Trigger
        Trigger trigger = TriggerBuilder.newTrigger()
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(10)) // 每隔10s执行一次,一直执行下去
                .startNow() // 立即开始
                .build();

        // 调度器执行
        scheduler.scheduleJob(jobDetail, trigger);
    }
}

6.3.5 控制台结果

Quartz定时任务框架(一)_第16张图片

你可能感兴趣的:(quartz,定时任务)