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),实现接口如下图:
-
有了任务,还需要一个能够实现出发任务去执行的触发器Trigger,Trigger最基本功能是执行task(Job)的执行时间,执行间隔,执行次数等
-
有了Job和Trigger后,如何将两者结合,并指定Trigger执行指定Job呢? 这个时候就有了调度器Schedule.
所以,Quartz的基本组成部分: - 调度器: Scheduler
- 任务: JobDetail
- 触发器: Tigger, 包括SimpleTirgger和CronTrigger
3. Quartz快速入门
3.1 入门Demo
3.1.1 导入依赖
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
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 控制台输出结果
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对象获取信息, 主要信息有:
4.3 JobDataMap
JobDataMap实现了JDK的Map接口, 可以以K-V形式存储数据. JobDetail, Trigger都可以使用JobDataMap来设置一些参数或信息
在Job执行execute()方法的时候, JobExecutionContext可以获取这些信息
控制台输出结果:
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中具体实现方法, 如图:
-
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
有两个具体实现类, 如图:
- StdSchedulerFactory: 默认值加载为当前工作目录下的”quartz.properties”属性文件. 如果加载失败, 会加载org/quartz包下的”quartz.properties”属性文件.
- DirectSchedulerfactory: 这个是为那些想绝对控制Scheduler实例而使用,没用过QAQ
4.6 如何禁止并发执行
项目中出现了一种情况,本来job执行时间只需要10s,但是由于数据库量增大之后,执行时间变成了60s,而我设置的间隔时间是30s,这样就会出现上次任务还没执行完成,下次任务就开始执行了。所以,在这种情况下,我们要禁止quart的并发操作.
3. Spring中将job的concurrent属性设为false, 默认为true
<bean id="scheduleJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="scheduleBusinessObject"/>
<property name="targetMethod" value="doIt"/>
<property name="concurrent" value="false"/>
</bean>
5. Quartz进阶(一)
5.1 实现Springboot整合Quartz
spring官网有具体的配置文档,实现quartz与springboot整合
5.1.1 spring.io官网查看文档
查看spring boot features
Spring Boot为使用Quartz调度器提供了多种方便,包括”Spring-Boot-Starter-Quartz”依赖。如果Quartz可用,则调度器通过SchedulerFactoryBean自动配置。
5.1.2 添加Spring-Boot-Starter-Quartz依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
5.1.3 创建Job
按照文档提供的案例,Job需要
继承
QuartzJobBean
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,查看运行结果
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,查看控制台输出结果:
5.1.5 总结
实现Springboot自动注入Scheduler方法有两个:
-
通过手动创建JobDetail和Trigger方式实现(
推荐
) - 通过配置类+Bean注解的方式实现(需要注意Bean的名称,如果Bean过多容易混淆)
6. SpringBoot整合Quartz(持久化到数据库)
6.1 背景
最近在做项目,项目中有个需求:需要使用定时任务,这个定时任务需要即时生效。
查看Quartz官网之后发现:Quartz提供两种基本作业存储类型:
- RAMJobStore :RAM也就是内存,默认情况下Quartz会将任务调度存在内存中,这种方式性能是最好的,因为内存的速度是最快的。不好的地方就是数据缺乏持久性,但程序崩溃或者重新发布的时候,所有运行信息都会丢失
-
JDBC作业存储:存到数据库之后,可以做单点也可以做集群,当任务多了之后,可以统一进行管理。关闭或者重启服务器,运行的信息都不会丢失。缺点就是运行速度快慢取决于连接数据库的快慢。
所以决定采用 JDBC作业存储的方式。
6.1 为什么要持久化
- 方便以后可以做集群
- 任务可以进行管理, 随时停止, 暂停, 修改
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 添加持久化相关依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
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 控制台结果