Quartz学习<一>
目录
一. Quartz 大致简介
-
Quartz 是完全由 java 开发的一个开源的任务日程管理系统
任务日程管理系统 换句话说就是:
一个预先确定的日程时间到达时,负责执行任务的一个系
-
Quartz用一个.jar 库文件,其包含了所有Quartz的核心功能,
-
这些功能有一个主要的接口: Schedule接口
它提供了简单的操作 例如:
将任务纳入日程或者从日程中取消
开始/停止/暂停日程进度
-
-
定时器的种类:
Quartz中有五中类型的Trigger:
SimpleTrigger : 用来触发只需执行一次或者在给定时间触发并且重复N次 且每次执行延迟一定时间的任务
CronTrigger : 按照日历触发,例如 每个周五 每个月的1号凌晨 2:30
DateIntervalTrigger
NthIncludedDayTrigger
Calendar 类(org.quartz.Calendar)
-
存储方式:
Quartz自身支持 两种存储方式:
RAMJobStore (顾明思议 存放在当前内存)
JDBCJobStore (通过jdbc实例到数据库)
对比:
存储类型 优点 缺点 RAMJobStore 不需要外部数据库,配置简单,运行速度快 因为调度程序信息存储在jvm 所以jvm程序停止运行时 将有丢失 且因为内存大小也有存储个数限制 JDBCJobStore 可以存储到数据库中可以控制事物 因为需要连接数据库 所以运行速度有所影响 表关系及解释
表名称 | 说明 |
qrtz_blob_triggers | Trigger作为Blob类型存储(用于Quartz用户用JDBC创建他们自己定制的Trigger类型,JobStore 并不知道如何存储实例的时候) |
qrtz_calendars | 以Blob类型存储Quartz的Calendar日历信息, quartz可配置一个日历来指定一个时间范围 |
qrtz_cron_triggers | 存储Cron Trigger,包括Cron表达式和时区信息。 |
qrtz_fired_triggers | 存储与已触发的Trigger相关的状态信息,以及相联Job的执行信息 |
qrtz_job_details | 存储每一个已配置的Job的详细信息 |
qrtz_locks | 存储程序的非观锁的信息(假如使用了悲观锁) |
qrtz_paused_trigger_graps | 存储已暂停的Trigger组的信息 |
qrtz_scheduler_state | 存储少量的有关 Scheduler的状态信息,和别的 Scheduler 实例(假如是用于一个集群中) |
qrtz_simple_triggers | 存储简单的 Trigger,包括重复次数,间隔,以及已触的次数 |
qrtz_triggers | 存储已配置的 Trigger的信息 |
qrzt_simprop_triggers |
-
核心类和关系
-
核心类
-
QuartzSchedulerThread:
负责执行向QuartzScheduler注册的触发Trigger的工作线程
-
ThreadPool :
Scheduler使用一个线程作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率
-
QuartzSchedulerResources :
包含穿件QuartzScheduler实例所需的所有资源(JobStore,ThreadPool等)
-
JobStore :
通过类实现的接口,这些类要为org.quartz.core.QuartzScheduler的使用提供一个org.quartz.Job和org.quartz.Trigger存储机制.作业和触发器的存储应该以其名称和组的组合为唯一性
-
QuartzScheduler :
Quartz的核心,他是org.quartz.Scheduler接口的间接实现,包含调度org.quartz.Jobs ,注册org.quartz.JobListener实例等的方法
-
Scheduler :
这是Quartz Scheduler的主要接口,代表一个独立运行容器. 调度程序维护JobDetails和触发器的注册表.一旦注册,调度程序负责执行作业,当她们的相关连的触发器触发(当她们的预定时间到达时 )
-
Trigger:
具有所有触发器通用属性的基本接口,描述了job执行的时间触发规则,
使用TriggerBuilder实例化实际触发器
-
JobDetail :
传递给定作业实例的详细信息属性.
JobDetails将使用JobBuilder创建/定义
-
Job :
表示要执行的"作业"的类的实现接口.
只有一个方法:
void execute(JobExecutionContext context);
(JobExecutionContext 提供调度上下文各种信息,运行时数据保存在jobDataMap中 )
Job 有个子接口StatefulJob,代表没有状态任务
有状态任务不可并发,前次任务没有执行完,后面任务则一直处于阻塞等待状态
-
一个job可以被多个Trigger 绑定,但是一个Trigger只能绑定一个job!
-
-
quartz.properties Quartz可更改配置
//调度标识名 集群中每一个实例都必须使用相同的名称 (区分特定的调度器实例)
org.quartz.scheduler.instanceName:DefaultQuartzScheduler
//ID设置为自动获取 每一个必须不同 (所有调度器实例中是唯一的)
org.quartz.scheduler.instanceId :AUTO
//数据保存方式为持久化
org.quartz.jobStore.class :org.quartz.impl.jdbcjobstore.JobStoreTX
//表的前缀
org.quartz.jobStore.tablePrefix : QRTZ_
//设置为TRUE不会出现序列化非字符串类到 BLOB 时产生的类版本问题
//org.quartz.jobStore.useProperties : true
//加入集群 true 为集群 false不是集群
org.quartz.jobStore.isClustered : false
//调度实例失效的检查时间间隔
org.quartz.jobStore.clusterCheckinInterval:20000
//容许的最大作业延长时间
org.quartz.jobStore.misfireThreshold :60000
//ThreadPool 实现的类名
org.quartz.threadPool.class:org.quartz.simpl.SimpleThreadPool
//线程数量
org.quartz.threadPool.threadCount : 10
//线程优先级
org.quartz.threadPool.threadPriority : 5(threadPriority 属性的最大值是常量 java.lang.Thread.MAX_PRIORITY,等于10。最小值为常量 java.lang.Thread.MIN_PRIORITY,为1)
//自创建父线程
//org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
//数据库别名
org.quartz.jobStore.dataSource : qzDS
//设置数据源
org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL:jdbc:mysql://localhost:3306/quartz
org.quartz.dataSource.qzDS.user:root
org.quartz.dataSource.qzDS.password:123456
org.quartz.dataSource.qzDS.maxConnection:10 -
JDBC插入表顺序
主要的JDBC操作类,执行sql顺序:
基本顺序:
记录工作内容
插入触发器列表
对应类型trigger规则入库
存储已触发job信息和trigge信息 Simple_trigger :插入顺序
qrtz_job_details ---> qrtz_triggers ---> qrtz_simple_triggers
qrtz_fired_triggers
Cron_Trigger:插入顺序
qrtz_job_details ---> qrtz_triggers ---> qrtz_cron_triggers
qrtz_fired_triggers
二 . Cron 表达式
-
为什么要使用cron表达式
我们之前提到 有五种触发器归我们使用
其中常用的 有 SimpleTrigger 和 CronTrigger
SimpleTrigger 是完全指定的时间反复进行工作的时间表
-
CronTrigger 却拥有着 充分的可根据日历预定的 方案 且它包含Simple方案中的 初始启动时间
例如:
每个星期五中午
每个工作日的早上10:30
周三周五 9:00-10:00 每五分钟一次
-
Cron Expressions
Cron 表达式并不是只是使用在 Quartz中的 ,实际上它作为一种专门的表达式也应用在Linux的定时任务中 ,以及在java中Spring的@Scheduled注解 也都使用了
Cron表达式是 字符串形式
Cron本质上是由七个 子表达式,描述个别细节的时间表 而这些子表达式是由空格分开的
子表达式:
位置 意义 有效值 可用特殊字符 1 Seconds 0-59 , - * / 2 Minutes 0-59 , - * / 3 Hours 0 - 23 , - * / 4 Day-of-Month 1 - 31 ( 注意一些特别的月份) , - * / ? L W 5 Month 0 - 11 或 字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV DEC” , - * / 6 Day-of-Week(每周) 1 - 7 或 字符串“SUN, MON, TUE, WED, THU, FRI, SAT”表示 * 注意: 1==SUN , - * / ? L # 7 Year(年 可选字段) empty 或者 1970-2099 , - * / -
特殊字符
显然通过子表达式并不能写出一个 重复执行的表达式
而特殊字符就是来解决当前问题的
特殊字符 :
符号 表示 举例说明 / 每 与当前子表达式结合使用占用一个子表达式位置 例: "3/15" 放在第二个子表达式位上, 表示第三分钟开始执行,每15分钟执行一次 ? 某一天 只存在与 Day-of-Month 和 Day-of-Week 中使用,来解决 这两个表达式的冲突问题 在其中一个子表达式有值的情况下 ?写在另一个表达式上表示匹配任意值,这样我们就不会再用* 去来表示匹配任意值了 例: 每月15号的早上4点 : "0 0 4 15 * ?" 每周五晚上11点: "0 0 23 ? * FRI" L 每月 或每周 的最后一天 只存在与 Day-of-Month 和 Day-of-Week 中使用, 在 Day-of-Month 子表达式中,“L”表示一个月的最后一天 在 Day-of-Week 子表达式中,“L”表示一个星期的最后一天,也就是SAT 例: “0 15 10 ? * 6L” 表示 每月最后一个星期五10:15分运行。 "0 15 10 2L * ?" 表示 每月倒数第二天10:15分运行。 W 最近工作日 只存在与 Day-of-Month 最近的工作日: 例: "0 15 10 15W * ?" 每个月距离15日最近的工作日 如 15日是周六则执行时间是14日 若15日是周日 则执行时间是16 如15号是工作日就15执行 就近匹配不会跨出当前月 # 第几个星期几 只存在与 Day-of-Week 中 每月第n个工作日 例:“0 15 10 ? * 6#3” 表示每个月第三个星期五 “0 15 10 ? * 4#2” 表示每个月第二个星期三 , 多个 例: "0 0 0,13,18,21 * * ?": 每天的0点、13点、18点、21点都执行一次: - 区间 例: "0 0-5 14 * * ?" : 在每天下午2点到下午2:05期间的每1分钟触发 * 补位符 补位 但是 注意: Day-of-Month 和 Day-of-Week 肯定有一个为 ? 也不能两个 ? 综合例子:
"0 0/30 0-4 ? 3,7 5#2 2018":
30分钟执行一次
凌晨的0-4 点
每个月
3 月和 7月
第二个周四
2018年
: 2018年 的三月和7月的第二个周四的凌晨0-4点 开始每30分钟执行一次
"0 30 4 10LW * ?":
第四位是 Day-of-Month L在此表示 每个月最后
10L表示每月的倒数第十天 (不一定是21号 月份不同倒数的第几天也就不同 ) W表示 附近的工作日
所以表示每个月离倒数第十天最近的工作日的凌晨4点30分执行一次
-