Quartz是一款基于Java实现的开源的任务调度库,体系结构如下:
核心组件包括:
org.quartz.Job
接口和它的execute()方法。扩展:
- 任务调度指系统中创建了 N 个任务,每个任务都有指定的时间进行执行,而这种多任务的执行策略就是任务调度。
x1<dependency>
2 <groupId>org.quartz-scheduler</groupId>
3 <artifactId>quartz</artifactId>
4 <version>2.3.2</version>
5</dependency>
6
91// @PersistJobDataAfterExecution
2public class TestJob implements Job {
3
4 public void execute(JobExecutionContext jobExecutionContext) {
5 String data = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
6 System.out.println("START DATA BACKUP, current time :" + data);
7 }
8}
9
默认情况下,Job是无状态的,每次都会创建新的实例,上下文中的JobDataMap也是新的。可以在Job类上加上@PersistJobDataAfterExecution
注解,则会变成有状态的Job,允许将数据传递给下一个Job,如统计Job执行次数。
341public class TestScheduler {
2 public static void main(String[] args) throws Exception {
3
4 // 1. 定义任务明细, 并与TestJob绑定
5 JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
6 // 任务名称, 任务组名称
7 .withIdentity("testJob", "testJobGroup")
8 .build();
9
10 // 2. 定义触发器, 立即执行一次, 接着5秒执行一次
11 Trigger trigger = TriggerBuilder.newTrigger()
12 // 触发器名称, 触发器组名称
13 .withIdentity("testTrigger", "testTriggerGroup")
14 // 立即执行一次
15 .startNow()
16 // 每隔5秒执行一次
17 .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
18 .build();
19
20 // 3. 获取调度器,并绑定任务和触发器
21 Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
22 scheduler.scheduleJob(jobDetail, trigger);
23
24 // 4. 开启调度
25 scheduler.start();
26 }
27}
28
29/** OUTPUT:
30START DATA BACKUP, current time :2024-04-24 10:49:48
31START DATA BACKUP, current time :2024-04-24 10:49:53
32START DATA BACKUP, current time :2024-04-24 10:49:58
33**/
34
401
2<project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0</modelVersion>
6
7 <groupId>org.example</groupId>
8 <artifactId>SpringBoot-Quartz-demo</artifactId>
9 <version>1.0-SNAPSHOT</version>
10
11 <!-- 引入SpringBoot父工程 -->
12 <parent>
13 <groupId>org.springframework.boot</groupId>
14 <artifactId>spring-boot-starter-parent</artifactId>
15 <version>2.1.1.RELEASE</version>
16 </parent>
17
18 <dependencies>
19 <!-- SpringMVC -->
20 <dependency>
21 <groupId>org.springframework.boot</groupId>
22 <artifactId>spring-boot-starter-web</artifactId>
23 </dependency>
24
25 <!-- Quartz -->
26 <dependency>
27 <groupId>org.springframework.boot</groupId>
28 <artifactId>spring-boot-starter-quartz</artifactId>
29 </dependency>
30
31 <!-- test -->
32 <dependency>
33 <groupId>org.springframework.boot</groupId>
34 <artifactId>spring-boot-starter-test</artifactId>
35 </dependency>
36
37 </dependencies>
38
39</project>
40
111// 注意:这里继承SpringBoot提供的 QuartzJobBean 类(也会间接继承Job类),就可以在Job中使用Spring容器了
2public class HelloJob extends QuartzJobBean {
3
4
5 protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
6 JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
7 String name = jobDataMap.getString("name");
8 System.out.println("Hello :" + name);
9 }
10}
11
331
2public class HelloController {
3
4
5 private Scheduler scheduler;
6
7 "/hello") (
8 public void helloJob(String name) throws SchedulerException {
9 // 使用 HelloJob 定义一个 JobDetail
10 JobDetail job = JobBuilder.newJob(HelloJob.class)
11 // 任务名、组名
12 .withIdentity("job11", "group1")
13 // 传递参数数据
14 .usingJobData("name", name)
15 .build();
16
17 // 定义一个简单的触发器: 每隔 1 秒执行 1 次,任务永不停止
18 SimpleTrigger trigger = TriggerBuilder.newTrigger()
19 .withIdentity("trigger1", "group1")
20 .withSchedule(SimpleScheduleBuilder
21 .simpleSchedule()
22 .withIntervalInSeconds(1)
23 .repeatForever()
24 ).build();
25
26 // 开始调度
27 scheduler.scheduleJob(job, trigger);
28 }
29}
30
31// 浏览器输入 http://localhost:8080/hello?name=phoenix 进行测试
32// 控制台会间隔1秒打印1次 Hello :phoenix
33
将 JobDetail 和 Trigger 注册为Bean,任务就会随Spring启动而自动触发执行,这对需要随程序启动而执行的作业非常有用。
331
2public class QuartzConfig {
3
4 // 将JobDetail注册为Bean
5
6 public JobDetail jobDetail() {
7 JobDetail job = JobBuilder.newJob(HelloJob.class)
8 .withIdentity("job22", "group2")
9 .usingJobData("name", "springboot")
10 .storeDurably()
11 .build();
12
13 return job;
14 }
15
16 // 将Trigger注册为Bean
17
18 public Trigger trigger() {
19 SimpleTrigger trigger = TriggerBuilder.newTrigger()
20 .forJob(jobDetail())
21 .withIdentity("trigger2", "group2")
22 .withSchedule(SimpleScheduleBuilder
23 .simpleSchedule()
24 .withIntervalInSeconds(1)
25 .repeatForever()
26 ).build();
27
28 return trigger;
29 }
30}
31
32// 上面配置在SpringBoot程序启动后会自动打印 Hello :springboot
33
集群模式可以防止单点故障,减少对业务的影响,同时可以分散单个节点的压力,提升集群整体处理能力。
Quartz基于数据库实现了集群模式,支持高可用、负载均衡(随机算法)、故障恢复等。
111<!-- 数据库相关依赖 -->
2<!-- 需要提前建立数据库,参考JDBCStore小节 -->
3<dependency>
4 <groupId>mysql</groupId>
5 <artifactId>mysql-connector-java</artifactId>
6 <version>8.0.29</version>
7</dependency>
8<dependency>
9 <groupId>org.springframework.boot</groupId>
10 <artifactId>spring-boot-starter-data-jpa</artifactId>
11</dependency>
271spring
2 datasource
3 driverClassName com.mysql.cj.jdbc.Driver
4 url jdbc mysql //106.53.120.230 3306/quartz
5 username root
6 password Hyx147741
7 quartz
8 job-store-type jdbc
9 properties
10 org
11 quartz
12 scheduler
13 instanceName ClusteredScheduler # 集群名,若使用集群功能,则每一个实例都要使用相同的名字
14 instanceId AUTO # 若是集群下,每个 instanceId 必须唯一,设置 AUTO 自动生成唯一 Id
15 threadPool
16 class org.quartz.simpl.SimpleThreadPool
17 threadCount25
18 threadPriority5
19 jobStore
20 class org.springframework.scheduling.quartz.LocalDataSourceJobStore
21 driverDelegateClass org.quartz.impl.jdbcjobstore.StdJDBCDelegate
22 tablePrefix QRTZ_
23 useProperties true # 使用字符串参数,避免了将非 String 类序列化为 BLOB 的类版本问题
24 isClustered true # 打开集群模式
25 clusterCheckinInterval 5000 # 集群存活检测间隔
26 misfireThreshold 60000 # 最大错过触发事件时间
27
221
2public class SchedulerConfig {
3
4
5 private DataSource dataSource;
6
7
8 private QuartzProperties quartzProperties;
9
10
11 public SchedulerFactoryBean schedulerFactoryBean() {
12 Properties properties = new Properties();
13 properties.putAll(quartzProperties.getProperties());
14
15 SchedulerFactoryBean factory = new SchedulerFactoryBean();
16 factory.setOverwriteExistingJobs(true);
17 factory.setDataSource(dataSource);
18 factory.setQuartzProperties(properties);
19 return factory;
20 }
21}
22
isClustered
属性设置为 true,并为每个单独的实例需要设置唯一的 instanceId
。
Job是任务的顶层接口,承载具体的业务逻辑,每次调用时都会创建新的实例对象。
JobDetail是任务的调度信息,可以构建和设置Job实例。
301// Job
2public interface Job {
3 // 执行任务
4 void execute(JobExecutionContext context) throws JobExecutionException;
5}
6
7// JobDetail
8public interface JobDetail extends Serializable, Cloneable {
9
10 // 任务ID(任务名称+组名称)
11 public JobKey getKey();
12
13 // 任务描述
14 public String getDescription();
15
16 // 获取Job实例
17 public Class<? extends Job> getJobClass();
18
19 // 任务状态信息
20 public JobDataMap getJobDataMap();
21
22 // 其它
23 public boolean isDurable();
24 public boolean isPersistJobDataAfterExecution();
25 public boolean isConcurrentExectionDisallowed();
26 public boolean requestsRecovery();
27 public Object clone();
28 public JobBuilder getJobBuilder();
29}
30
Job执行的上下文信息,可以访问到 Quartz 运行时的环境以及 Job 本身的明细数据。
481public interface JobExecutionContext {
2
3 // 调度器
4 public Scheduler getScheduler();
5
6 // 触发器
7 public Trigger getTrigger();
8
9 // 日历
10 public Calendar getCalendar();
11
12 // JobDetail
13 public JobDetail getJobDetail();
14
15 // Job实例
16 public Job getJobInstance();
17
18 // 是否为被恢复的作业
19 public boolean isRecovering();
20
21 // 合并后的JobDataMap
22 public JobDataMap getMergedJobDataMap();
23
24 // 实际触发时间
25 public Date getFireTime();
26
27 // 计划触发时间
28 public Date getScheduledFireTime();
29
30 // 业务代码的执行结果
31 public Object getResult();
32 public void setResult(Object result);
33
34 // Job的运行时间(ms),在实际完成或异常结束前为-1。
35 public long getJobRunTime();
36
37 // 上下文Map,可用于监听器和Job之间的数据传递等场景
38 public void put(Object key, Object value);
39 public Object get(Object key);
40
41 // 其它
42 public Date getPreviousFireTime();
43 public Date getNextFireTime();
44 public String getFireInstanceId();
45 public TriggerKey getRecoveringTriggerKey() throws IllegalStateException;
46 public int getRefireCount();
47
48}
一个键为String,值为Object类型的Map,用于存储和传递数据,存在于JobDetail和Trigger等中。
161// 1. 创建JobDetail时进行设置
2JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
3 .withIdentity("testJob", "testJobGroup")
4 // 任务数据
5 .usingJobData("key01", "jobDetail01")
6 .build();
7
8// 2. 定义触发器时进行设置
9Trigger trigger = TriggerBuilder.newTrigger()
10 .withIdentity("testTrigger", "testTriggerGroup")
11 .startNow()
12 .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
13 // 触发器数据
14 .usingJobData("key01", "trigger01")
15 .build();
16
在Job类中,可以通过JobExecutionContext获取设置的数据,或通过Quartz框架进行注入。
221public class TestJob implements Job {
2
3 // 1.1 存储数据的变量
4 private String key01;
5
6 // 1.2 注入方法(检测到对应setter方法存在时,Quartz框架会自动注入)
7 public void setKey01(String key01) {
8 this.key01 = key01;
9 }
10
11
12 public void execute(JobExecutionContext context) throws JobExecutionException {
13 // 2. 方式二:使用 JobExecutionContext 获取设置的数据
14 System.out.println(context.getJobDetail().getJobDataMap().get("key01"));
15 System.out.println(context.getTrigger().getJobDataMap().get("key01"));
16
17 // 1.3 方式一:通过注入的方式使用设置的数据
18 // 注意:当JobDetail和Trigger设置的key冲突时,优先使用Trigger的
19 System.out.println(key01);
20 }
21}
22
Trigger用于指定任务触发的时机,其接口和实现类如下,我们一般使用 SimpleTrigger
和 CronTrigger
两种。
SimpleTrigger适用于在特定的日期(或时间)启动,以固定的间隔时间重复执行 n 次的Job任务。
181Trigger trigger = TriggerBuilder.newTrigger()
2 // 触发器名称, 触发器组名称
3 .withIdentity("testTrigger", "testTriggerGroup")
4 // 开始时间
5 .startAt(new Date()) // startNow() 表示开始时间为当前时间
6 // 结束时间
7 .endAt(new Date())
8 // Simple策略
9 .withSchedule(
10 SimpleScheduleBuilder
11 // 间隔5s
12 .repeatSecondlyForever(5)
13 // 最多执行10次
14 .withRepeatCount(10)
15 )
16 .endAt(new Date())
17 .build();
18
CronTrigger是基于日历的作业调度器,可以做到某个时间点执行,例如“每天的凌晨1点”、“每个工作日的12点”等。
41Trigger trigger = TriggerBuilder.newTrigger()
2 .withIdentity("testTrigger", "testTriggerGroup")
3 .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * 6 4 ?"))
4 .build();
调度器(Scheduler)负责将任务(Job)和触发器(Trigger)整合起来,基于Trigger设定的时间来执行Job。
231// 调度器配置
2Properties properties = new Properties();
3properties.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, "org.quartz.simpl.SimpleThreadPool"); // 线程池定义
4properties.put("org.quartz.threadPool.threadCount", "5"); // 默认Scheduler的线程数
5
6// 获取调度器
7StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
8stdSchedulerFactory.initialize(properties);
9Scheduler scheduler = stdSchedulerFactory.getScheduler();
10
11// 组合任务和触发器
12Date date = scheduler.scheduleJob(jobDetail, trigger); // 返回调度器开始的时间
13
14// 启动任务调度
15scheduler.start();
16
17// 将任务调度挂起(暂停)
18scheduler.standby();
19
20// 将任务调度关闭
21shutdown(true); //表示等待所有正在执行的job执行完毕之后,再关闭Scheduler
22shutdown(false); //表示直接关闭Scheduler
23
41// 创建一个标准调度器
2// 默认加载 quartz.properties 文件中的配置,可由 org.quartz.properties 属性指定文件名
3Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
4
quartz.properties 文件配置示例如下,更多配置可参考 StdSchedulerFactory 类代码。
131org.quartz.scheduler.instanceName: DefaultQuartzScheduler
2org.quartz.scheduler.rmi.export: false
3org.quartz.scheduler.rmi.proxy: false
4org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
5
6org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
7org.quartz.threadPool.threadCount: 10
8org.quartz.threadPool.threadPriority: 5
9org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
10
11org.quartz.jobStore.misfireThreshold: 60000
12org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
13
监听器(Listener)用于监听特定事件的发生,以便做出对应的处理,包括任务监听器、触发器监听器、调度器监听器。
271// JobListener
2public class TestJobListener implements JobListener {
3
4 public String getName() {
5 return "任务监控器01";
6 }
7
8
9 public void jobToBeExecuted(JobExecutionContext context) {
10 String jobName = context.getJobDetail().getKey().getName();
11 System.out.println("任务[" + jobName + "]执行前处理");
12 }
13
14
15 public void jobExecutionVetoed(JobExecutionContext context) {
16 String jobName = context.getJobDetail().getKey().getName();
17 System.out.println("任务[" + jobName + "]执行前被TriggerListerner否决");
18 }
19
20
21 public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
22 String jobName = context.getJobDetail().getKey().getName();
23 System.out.println("任务[" + jobName + "]执行后处理");
24 }
25}
26
27
381public class TestTriggerListener implements TriggerListener {
2
3 public String getName() {
4 return "触发器监听器01";
5 }
6
7
8 public void triggerFired(Trigger trigger, JobExecutionContext context) {
9 String triggerName = trigger.getKey().getName();
10 System.out.println("触发器[" + triggerName + "]被触发,将执行Job#execute()方法");
11 }
12
13
14 public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
15 if (System.currentTimeMillis() % 2 == 0) {
16 String triggerName = trigger.getKey().getName();
17 System.out.println("触发器[" + triggerName + "]否决了Job#execute()方法的执行");
18 return true;
19 } else {
20 String triggerName = trigger.getKey().getName();
21 System.out.println("触发器[" + triggerName + "]没有否决Job#execute()方法的执行");
22 return false;
23 }
24 }
25
26
27 public void triggerMisfired(Trigger trigger) {
28 String triggerName = trigger.getKey().getName();
29 System.out.println("触发器[" + triggerName + "]错过了触发时机");
30 }
31
32
33 public void triggerComplete(Trigger trigger, JobExecutionContext context, Trigger.CompletedExecutionInstruction triggerInstructionCode) {
34 String triggerName = trigger.getKey().getName();
35 System.out.println("触发器[" + triggerName + "]被触发且任务执行完成");
36 }
37}
38
1031public class TestSchedulerListener implements SchedulerListener {
2
3
4 public void jobScheduled(Trigger trigger) {
5
6 }
7
8
9 public void jobUnscheduled(TriggerKey triggerKey) {
10
11 }
12
13
14 public void triggerFinalized(Trigger trigger) {
15
16 }
17
18
19 public void triggerPaused(TriggerKey triggerKey) {
20
21 }
22
23
24 public void triggersPaused(String triggerGroup) {
25
26 }
27
28
29 public void triggerResumed(TriggerKey triggerKey) {
30
31 }
32
33
34 public void triggersResumed(String triggerGroup) {
35
36 }
37
38
39 public void jobAdded(JobDetail jobDetail) {
40
41 }
42
43
44 public void jobDeleted(JobKey jobKey) {
45
46 }
47
48
49 public void jobPaused(JobKey jobKey) {
50
51 }
52
53
54 public void jobsPaused(String jobGroup) {
55
56 }
57
58
59 public void jobResumed(JobKey jobKey) {
60
61 }
62
63
64 public void jobsResumed(String jobGroup) {
65
66 }
67
68
69 public void schedulerError(String msg, SchedulerException cause) {
70
71 }
72
73
74 public void schedulerInStandbyMode() {
75
76 }
77
78
79 public void schedulerStarted() {
80
81 }
82
83
84 public void schedulerStarting() {
85
86 }
87
88
89 public void schedulerShutdown() {
90
91 }
92
93
94 public void schedulerShuttingdown() {
95
96 }
97
98
99 public void schedulingDataCleared() {
100
101 }
102}
103
421public class TestScheduler4 {
2 public static void main(String[] args) throws SchedulerException {
3
4 // 1. 定义任务明细, 并与TestJob绑定
5 JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
6 .withIdentity("testJob", "testJobGroup")
7 .build();
8
9 // 2. 定义触发器, 立即执行一次, 接着5秒执行一次
10 Trigger trigger = TriggerBuilder.newTrigger()
11 .withIdentity("testTrigger", "testTriggerGroup")
12 .startNow()
13 .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
14 .build();
15
16 // 3. 获取调度器,并绑定任务和触发器
17 Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
18 scheduler.scheduleJob(jobDetail, trigger);
19
20 // 4. 添加全局监听器
21 ListenerManager listenerManager = scheduler.getListenerManager();
22 listenerManager.addJobListener(new TestJobListener(), EverythingMatcher.allJobs());
23 listenerManager.addTriggerListener(new TestTriggerListener(), EverythingMatcher.allTriggers());
24 listenerManager.addSchedulerListener(new TestSchedulerListener());
25
26 // 5. 开启调度
27 scheduler.start();
28 }
29}
30
31
32触发器[testTrigger]被触发,将执行Job#execute()方法
33触发器[testTrigger]否决了Job#execute()方法的执行
34任务[testJob]执行前被TriggerListerner否决
35
36触发器[testTrigger]被触发,将执行Job#execute()方法
37触发器[testTrigger]没有否决Job#execute()方法的执行
38任务[testJob]执行前处理
39START DATA BACKUP, current time :2024-05-07 17:45:05
40任务[testJob]执行后处理
41触发器[testTrigger]被触发且任务执行完成
42
作业存储(JobStore)用于定义Quartz运行时任务的存储方式。
RAMJobStore是基于内存的存储模式,调度信息保存在内存中,性能较高,但应用程序结束或崩溃时数据将丢失。
31# 设置为内存模式(需配合StdSchedulerFactory使用)
2org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
3
JDBCJobStore是基于数据库的存储模式,调度信息保存在数据库中,可以持久化保存调度信息,但是性能取决于数据库性能。
下面是使用步骤:
建库建表:
11-- 见附录
引入数据库依赖:
61<!-- 添加数据库依赖 -->
2<dependency>
3 <groupId>mysql</groupId>
4 <artifactId>mysql-connector-java</artifactId>
5 <version>8.0.29</version>
6</dependency>
修改配置文件:
221org.quartz.scheduler.instanceName: DefaultQuartzScheduler
2org.quartz.scheduler.rmi.export: false
3org.quartz.scheduler.rmi.proxy: false
4org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
5
6org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
7org.quartz.threadPool.threadCount: 10
8org.quartz.threadPool.threadPriority: 5
9org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
10
11org.quartz.jobStore.misfireThreshold: 60000
12org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
13org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
14org.quartz.jobStore.tablePrefix = QRTZ_
15org.quartz.jobStore.dataSource = myDS
16
17org.quartz.dataSource.myDS.driver = com.mysql.cj.jdbc.Driver
18org.quartz.dataSource.myDS.URL = jdbc:mysql://127.0.0.1:3306/quartz_demo
19org.quartz.dataSource.myDS.user = root
20org.quartz.dataSource.myDS.password = test123456
21org.quartz.dataSource.myDS.maxConnections = 30
22
执行任务调度后,可以在 QRTZ_JOB_DETAILS 表查看任务明细数据。
Cron表达式由7个子表达式组成,分别是:
字段 | 是否必填 | 允许值 | 可用特殊字符 |
---|---|---|---|
秒 | 是 | 0-59 | , - * / |
分 | 是 | 0-59 | , - * / |
时 | 是 | 0-23 | , - * / |
日(月中的哪几天) | 是 | 1-31 | , - * / ? L C W |
月 | 是 | 1-12 或 JAN-DEC | , - * / |
周(周中的哪几天) | 是 | 1-7 或 SUN-SAT | , - * / ? L C # |
年 | 否 | 不填写 或 1970-2099 | , - * / |
可用的特殊字符及含义如下:
特殊字符含义 | |
---|---|
* | 可用在所有字段中,表示对应时间域的每一个时刻,如:在分钟字段时,表示“每分钟” |
? | 该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符 |
- | 表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12 |
, | 表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五 |
/ | x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y |
L | 该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五 |
W | 该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围 |
# | 该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发 |
Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。
181"0 0 10,14,16 * * ?" 每天上午10点,下午2点,4点
2"0 0/30 9-17 * * ?" 朝九晚五工作时间内每半小时,从0分开始每隔30分钟发送一次
3"0 0 12 ? * WED" 表示每个星期三中午12点
4"0 0 12 * * ?" 每天中午12点触发
5"0 15 10 ? * *" 每天上午10:15触发
6"0 15 10 * * ?" 每天上午10:15触发
7"0 15 10 * * ? *" 每天上午10:15触发
8"0 15 10 * * ? 2005" 2005年的每天上午10:15触发
9"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发
10"0 0/55 14 * * ?" 在每天下午2点到下午2:55期间,从0开始到55分钟触发
11"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发
12"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发
13"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发
14"0 15 10 15 * ?" 每月15日上午10:15触发
15"0 15 10 L * ?" 每月最后一日的上午10:15触发
16"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发
17"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发
18"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发
1861-- Quartz表结构脚本(MySql版)
2-- Quartz代码中使用大写表名,建表时注意区分表名大小写
3-- 表字段含义参考:https://blog.csdn.net/sqlgao22/article/details/100697214
4
5-- 建库
6-- drop database if exists quartz;
7-- create database `quartz` character set 'utf8' collate 'utf8_general_ci';
8use quartz;
9
10-- 调度器信息
11DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
12CREATE TABLE QRTZ_SCHEDULER_STATE (
13 SCHED_NAME VARCHAR(120) NOT NULL,
14 INSTANCE_NAME VARCHAR(200) NOT NULL,
15 LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
16 CHECKIN_INTERVAL BIGINT(13) NOT NULL,
17 PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
18) ENGINE=INNODB;
19
20-- 任务信息
21DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
22CREATE TABLE QRTZ_JOB_DETAILS(
23 SCHED_NAME VARCHAR(120) NOT NULL,
24 JOB_NAME VARCHAR(200) NOT NULL,
25 JOB_GROUP VARCHAR(200) NOT NULL,
26 DESCRIPTION VARCHAR(250) NULL,
27 JOB_CLASS_NAME VARCHAR(250) NOT NULL,
28 IS_DURABLE VARCHAR(1) NOT NULL,
29 IS_NONCONCURRENT VARCHAR(1) NOT NULL,
30 IS_UPDATE_DATA VARCHAR(1) NOT NULL,
31 REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
32 JOB_DATA BLOB NULL,
33 PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
34) ENGINE=INNODB;
35CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
36CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
37
38-- 日历信息
39DROP TABLE IF EXISTS QRTZ_CALENDARS;
40CREATE TABLE QRTZ_CALENDARS (
41 SCHED_NAME VARCHAR(120) NOT NULL,
42 CALENDAR_NAME VARCHAR(200) NOT NULL,
43 CALENDAR BLOB NOT NULL,
44 PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
45) ENGINE=INNODB;
46
47-- 程序的悲观锁信息
48DROP TABLE IF EXISTS QRTZ_LOCKS;
49CREATE TABLE QRTZ_LOCKS (
50 SCHED_NAME VARCHAR(120) NOT NULL,
51 LOCK_NAME VARCHAR(40) NOT NULL,
52 PRIMARY KEY (SCHED_NAME,LOCK_NAME)
53) ENGINE=INNODB;
54
55-- 已配置的触发器信息
56DROP TABLE IF EXISTS QRTZ_TRIGGERS;
57CREATE TABLE QRTZ_TRIGGERS (
58 SCHED_NAME VARCHAR(120) NOT NULL,
59 TRIGGER_NAME VARCHAR(200) NOT NULL,
60 TRIGGER_GROUP VARCHAR(200) NOT NULL,
61 JOB_NAME VARCHAR(200) NOT NULL,
62 JOB_GROUP VARCHAR(200) NOT NULL,
63 DESCRIPTION VARCHAR(250) NULL,
64 NEXT_FIRE_TIME BIGINT(13) NULL,
65 PREV_FIRE_TIME BIGINT(13) NULL,
66 PRIORITY INTEGER NULL,
67 TRIGGER_STATE VARCHAR(16) NOT NULL,
68 TRIGGER_TYPE VARCHAR(8) NOT NULL,
69 START_TIME BIGINT(13) NOT NULL,
70 END_TIME BIGINT(13) NULL,
71 CALENDAR_NAME VARCHAR(200) NULL,
72 MISFIRE_INSTR SMALLINT(2) NULL,
73 JOB_DATA BLOB NULL,
74 PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
75 FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
76 REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
77) ENGINE=INNODB;
78CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
79CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
80CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
81CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
82CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
83CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
84CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
85CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
86CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
87CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
88CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
89CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
90
91-- 简单触发器信息
92DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
93CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
94 SCHED_NAME VARCHAR(120) NOT NULL,
95 TRIGGER_NAME VARCHAR(200) NOT NULL,
96 TRIGGER_GROUP VARCHAR(200) NOT NULL,
97 REPEAT_COUNT BIGINT(7) NOT NULL,
98 REPEAT_INTERVAL BIGINT(12) NOT NULL,
99 TIMES_TRIGGERED BIGINT(10) NOT NULL,
100 PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
101 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
102 REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
103) ENGINE=INNODB;
104
105-- Cron触发器信息
106DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
107CREATE TABLE QRTZ_CRON_TRIGGERS (
108 SCHED_NAME VARCHAR(120) NOT NULL,
109 TRIGGER_NAME VARCHAR(200) NOT NULL,
110 TRIGGER_GROUP VARCHAR(200) NOT NULL,
111 CRON_EXPRESSION VARCHAR(120) NOT NULL,
112 TIME_ZONE_ID VARCHAR(80),
113 PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
114 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
115 REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
116) ENGINE=INNODB;
117
118-- CalendarIntervalTrigger和DailyTimeIntervalTrigger信息
119DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
120CREATE TABLE QRTZ_SIMPROP_TRIGGERS (
121 SCHED_NAME VARCHAR(120) NOT NULL,
122 TRIGGER_NAME VARCHAR(200) NOT NULL,
123 TRIGGER_GROUP VARCHAR(200) NOT NULL,
124 STR_PROP_1 VARCHAR(512) NULL,
125 STR_PROP_2 VARCHAR(512) NULL,
126 STR_PROP_3 VARCHAR(512) NULL,
127 INT_PROP_1 INT NULL,
128 INT_PROP_2 INT NULL,
129 LONG_PROP_1 BIGINT NULL,
130 LONG_PROP_2 BIGINT NULL,
131 DEC_PROP_1 NUMERIC(13,4) NULL,
132 DEC_PROP_2 NUMERIC(13,4) NULL,
133 BOOL_PROP_1 VARCHAR(1) NULL,
134 BOOL_PROP_2 VARCHAR(1) NULL,
135 PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
136 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
137 REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
138) ENGINE=INNODB;
139
140-- 触发器作为BLOB类型存储
141DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
142CREATE TABLE QRTZ_BLOB_TRIGGERS (
143 SCHED_NAME VARCHAR(120) NOT NULL,
144 TRIGGER_NAME VARCHAR(200) NOT NULL,
145 TRIGGER_GROUP VARCHAR(200) NOT NULL,
146 BLOB_DATA BLOB NULL,
147 PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
148 INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
149 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
150 REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
151) ENGINE=INNODB;
152
153-- 已触发的触发器信息
154DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
155CREATE TABLE QRTZ_FIRED_TRIGGERS (
156 SCHED_NAME VARCHAR(120) NOT NULL,
157 ENTRY_ID VARCHAR(95) NOT NULL,
158 TRIGGER_NAME VARCHAR(200) NOT NULL,
159 TRIGGER_GROUP VARCHAR(200) NOT NULL,
160 INSTANCE_NAME VARCHAR(200) NOT NULL,
161 FIRED_TIME BIGINT(13) NOT NULL,
162 SCHED_TIME BIGINT(13) NOT NULL,
163 PRIORITY INTEGER NOT NULL,
164 STATE VARCHAR(16) NOT NULL,
165 JOB_NAME VARCHAR(200) NULL,
166 JOB_GROUP VARCHAR(200) NULL,
167 IS_NONCONCURRENT VARCHAR(1) NULL,
168 REQUESTS_RECOVERY VARCHAR(1) NULL,
169 PRIMARY KEY (SCHED_NAME,ENTRY_ID)
170) ENGINE=INNODB;
171CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
172CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
173CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
174CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
175CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
176CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
177
178-- 已暂停的触发器信息
179DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
180CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
181 SCHED_NAME VARCHAR(120) NOT NULL,
182 TRIGGER_GROUP VARCHAR(200) NOT NULL,
183 PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
184) ENGINE=INNODB;
185
186COMMIT;