勿以恶小而为之,勿以善小而不为--------------------------刘备
劝诸君,多行善事积福报,莫作恶
上一章简单介绍了 SSM整合Quartz(八) ,如果没有看过,请观看上一章
本文参考了 阿飞云前辈的文章: 精进 Quartz—Quartz大致介绍(一)
一. Quartz 持久化之前的准备
一.一 为什么要持久化?
以前写的 Demo,包括 SSM整合 Quartz 框架,都不是持久化的,都是存储在内存里面的。 当程序突然被中断时,如断电,内存超出时,很有可能造成任务的丢失。 可以将调度信息存储到数据库里面,进行持久化,当程序被中断后,再次启动,仍然会保留中断之前的数据,继续执行,而并不是重新开始。
一.二 两种存储类型
Quartz 框架提供了两种任务存储的类型, 分别为 RAMJobStore 和 JobStoreTX
类型 | 优点 | 缺点 |
---|---|---|
RAMJobStore | 存储在内存里,配置简单,运行速度快 | 当程序停止时,调度信息会丢失。 可以存储的 JobDetail和 Trigger 有数量限制 |
JobStoreTX | 存储在数据库里面,当程序中断时,调度信息不会丢失 支持事务,支持集群。 再次启动时,会恢复因程序关闭,重启 而错过的任务。 | 运行速度较慢, 具体与连接数据库的速度有关 |
一.三 创建 持久化表
一.三.一 创建持久化表语句
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;
CREATE TABLE QRTZ_JOB_DETAILS
(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(100) NOT NULL,
JOB_GROUP VARCHAR(100) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE QRTZ_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(100) NOT NULL,
TRIGGER_GROUP VARCHAR(100) NOT NULL,
JOB_NAME VARCHAR(100) NOT NULL,
JOB_GROUP VARCHAR(100) NOT NULL,
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_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(100) 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)
);
CREATE TABLE QRTZ_SIMPLE_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(100) NOT NULL,
TRIGGER_GROUP VARCHAR(100) 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)
);
CREATE TABLE QRTZ_CRON_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(100) NOT NULL,
TRIGGER_GROUP VARCHAR(100) NOT NULL,
CRON_EXPRESSION VARCHAR(100) NOT NULL,
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)
);
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(100) NOT NULL,
TRIGGER_GROUP VARCHAR(100) 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)
);
CREATE TABLE QRTZ_BLOB_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(100) NOT NULL,
TRIGGER_GROUP VARCHAR(100) NOT NULL,
BLOB_DATA BLOB 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)
);
CREATE TABLE QRTZ_CALENDARS
(
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(100) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(100) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
CREATE TABLE QRTZ_FIRED_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(100) NOT NULL,
TRIGGER_GROUP VARCHAR(100) NOT NULL,
INSTANCE_NAME VARCHAR(100) 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(100) NULL,
JOB_GROUP VARCHAR(100) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);
CREATE TABLE QRTZ_SCHEDULER_STATE
(
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(100) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);
CREATE TABLE QRTZ_LOCKS
(
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);
commit;
放置到 老蝴蝶本地 quartz 数据库里面。
运行成功之后
共11个表,表名均以 qrtz_ 为前缀。
一.三.二 表关系
说明,从阿飞云前辈的博客里面复制的。
一.三.三 持久化表解释
说明,从阿飞云前辈的博客里面复制的。
表名 | 表作用 |
---|---|
qrtz_blob_triggers | 作为 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_grps | 存储已暂停的Trigger组的信息 |
qrtz_scheduler_state | 存储少量的有关 Scheduler的状态信息,和别的 Scheduler 实例(假如是用于一个集群中) |
qrtz_simple_triggers | 存储简单的 Trigger,包括重复次数,间隔,以及已触的次数 |
qrtz_simprop_triggers | 未知 |
qrtz_triggers | 存储已配置的 Trigger 的信息 |
一般项目中配置的都是 Cron 触发器, 需要记录 qrtz_cron_triggers 和 qrtz_job_details, qrtz_triggers 三个常用表。
二. Quartz 框架的持久化
二.一 复制配置信息 quartz.properties
Quartz 框架在运行时,需要一个配置文件 quartz.properties, 里面放置基本的配置信息。
该文件位于 quartz.jar 下面的 org.quartz 包下。
将该文件复制到 src/main/resource 目录下
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
我们可以修改 resource目录下的 quartz.properties 属性文件内容 进行自定义配置。
org.quartz.jobStore.class,指的是 Quartz 的存储类型, 默认是 RAMJobStore, 存储在内存里面。
关于 quartz.properties 配置文件的信息,大家可以看 W3CSchool 关于 Quartz 部分的文章。
二.二 将类型转换成 JobStoreTX
JobStoreTX 全称是: org.quartz.impl.jdbcjobstore.JobStoreTX
# 注释掉内存存储
# org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#持久化
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
二.三 配置驱动代理
##驱动代理为 标准的jdbc
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
StdJDBCDelegate 为标准的jdbc。
二.四 配置数据库表前缀和数据源
#数据库表前缀
org.quartz.jobStore.tablePrefix:qrtz_
#数据源
org.quartz.jobStore.dataSource:yjlDB
#JDBC驱动
org.quartz.dataSource.yjlDB.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.yjlDB.URL:jdbc:mysql://localhost:3306/quartz
org.quartz.dataSource.yjlDB.user:root
org.quartz.dataSource.yjlDB.password:您的数据库密码
其中, yjlDB 是数据源名称, 可以任意起一个, 但要与下面的 dataSource.Xxx 保持一致。
注意,这个时候,只是简单的 JavaSE 配置,并没有与 Spring进行整合,
所以数据库直接写在 quartz.properties 属性文件里面。
当与Spring 进行整合之后,直接拿 applicationContext-dao.xml 里面的数据源 dataSource 即可。
当配置 org.quartz.dataSource.yjlDB.maxConnection:10 时会报错,说没有 setMaxConnection() 方法。
这儿就不配置 org.quartz.dataSource.yjlDB.maxConnection 的值了。
二.五 最终 quartz.properties 配置文件内容
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
# 注释掉内存存储
# org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#持久化
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
##驱动代理为 标准的jdbc
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#数据库表前缀
org.quartz.jobStore.tablePrefix:qrtz_
#数据
org.quartz.jobStore.dataSource:yjlDB
#JDBC驱动
org.quartz.dataSource.yjlDB.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.yjlDB.URL:jdbc:mysql://localhost:3306/quartz
org.quartz.dataSource.yjlDB.user:root
org.quartz.dataSource.yjlDB.password:abc123
三. 持久化演示
三.一 编写任务 MyJobStoreTX
package com.yjl.jdbc;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
*
* @author 两个蝴蝶飞
* 简单的 JobStoreTx 存储时的任务
*
*/
public class MyJobStoreTX implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String nowDate=sdf.format(new Date());
System.out.println("MyJobStoreTX 备份数据库的时间是:"+nowDate);
}
}
三.二 编写主程序 MyJobStoreTxDemo
//测试 JobStoreTX 存储
public class MyJobStoreTxDemo {
public static void main(String[] args) throws Exception {
// 获取Scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
JobDetail jobDetail = JobBuilder.newJob(MyJobStoreTX.class)
.withIdentity("jobTX1", "groupTX1")
.storeDurably(true)
.build();
// 创建 Trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("triggerTX1", "groupTX1") // 设置标识
.startNow()
// 每隔3秒执行一次
.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
.build();
// 关联 job和 trigger
scheduler.scheduleJob(jobDetail, trigger);
// 启动 scheduler
scheduler.start();
}
}
三.三 运行程序,看控制台打印输出
每隔两秒,运行一次。
查看数据库的 qrtz_cron_triggers 表内容:
查看数据库的 qrtz_job_details 表内容:
查看数据库的 qrtz_triggers 表内容:
将 JobDetail, Trigger 的内容放置到了数据库里面,进行了持久性的保存。
三.四 关闭程序后,再次运行
再次运行
Exception in thread “main” org.quartz.ObjectAlreadyExistsException:
Unable to store Job : ‘groupTX1.jobTX1’, because one already exists with this identification.
说已经存在了, 即 JobDetail的 组名称.job名称, 两个唯一确定一个JobDetail 任务对象。
与平常项目中的操作一样,在创建之前,先进行验证, 如果存在了,就执行以前的那个,如果不存在,就创建。
三.五 创建前验证是否存在的主程序 MyJobStoreTxDemo
//测试 JobStoreTX 存储
public class MyJobStoreTxDemo {
public static void main(String[] args) throws Exception {
// 获取Scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//定义JobKey
JobKey jobKey=new JobKey("jobTX1", "groupTX1");
//判断是否存在,查询所有 的触发器
List<? extends Trigger> triggers1 = scheduler.getTriggersOfJob(jobKey);
if(triggers1.size() > 0){
for (Trigger tg : triggers1) {
// 根据类型判断
if ((tg instanceof CronTrigger) || (tg instanceof SimpleTrigger)) {
// 恢复job运行
scheduler.resumeJob(jobKey);
}
}
scheduler.start();
}else{
JobDetail jobDetail = JobBuilder.newJob(MyJobStoreTX.class)
.withIdentity(jobKey)
.storeDurably(true)
.build();
// 创建 Trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("triggerTX1", "groupTX1") // 设置标识
.startNow()
// 每隔3秒执行一次
.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
.build();
// 关联 job和 trigger
scheduler.scheduleJob(jobDetail, trigger);
// 启动 scheduler
scheduler.start();
}
}
}
三.六 重新启动,查看控制台输出
正常启动作业任务。
四. Spring 配置 Quartz 持久化
与 Spring 配置 Quartz 差不多,仍然使用以前的例子。
注意,这个时候,将 quartz.properties 的数据源配置暂时移除, 数据源的配置交给 Spring 管理了。
# 注释掉内存存储
# org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#持久化
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
##驱动代理为 标准的jdbc
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#数据库表前缀
org.quartz.jobStore.tablePrefix:qrtz_
#数据源交给 spring 进行管理
#org.quartz.jobStore.dataSource:yjlDB
#JDBC驱动
#org.quartz.dataSource.yjlDB.driver:com.mysql.jdbc.Driver
#org.quartz.dataSource.yjlDB.URL:jdbc:mysql://localhost:3306/quartz
#org.quartz.dataSource.yjlDB.user:root
#org.quartz.dataSource.yjlDB.password:abc123
将 MyJob.java 的 输出语句改变一下,更好的区分。
System.out.println("spring管理持久化 备份数据库的时间是:"+dateString);
四.一 配置静态的任务
<!-- 定义 JobDetail, 所用的bean 为 JobDetailFactoryBean -->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 任务名 -->
<property name="name" value="job1"></property>
<!-- 组名 -->
<property name="group" value="group1"></property>
<!-- 关联任务 -->
<property name="jobClass" value="com.yjl.job.MyJob"></property>
<!-- 必须是true, 如果是false的话,当这个jobDetail没有被Trigger关联时,会删除 -->
<property name="durability" value="true"></property>
<!-- 不设置 applicationContextJobDataKey 属性-->
</bean>
<!-- 定义 cron 触发器 -->
<bean id="trigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 配置触发器的名称 -->
<property name="name" value="trigger1"></property>
<!-- 配置触发器的组名 -->
<property name="group" value="group1"></property>
<!-- 配置关联的 JobDetail -->
<property name="jobDetail" ref="jobDetail"></property>
<!-- 配置 cron 表达式 ,每2秒触发一次-->
<property name="cronExpression" value="0/2 * * * * ?"></property>
</bean>
<!-- 配置 scheduler 调度器 -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="trigger1"/>
</list>
</property>
<!-- 引入 quartz的配置信息 -->
<!-- <property name="configLocation" value="classpath:quartz.properties"></property> -->
<property name="quartzProperties">
<value>
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
<!-- org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore -->
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
<!--驱动-->
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
<!-- 数据库表前缀 -->
org.quartz.jobStore.tablePrefix:qrtz_
</value>
</property>
<!-- 配置数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
每2s 触发一次。
四.二 重启服务器,运行
正常的启动。
查看数据库, qrtz_cron_triggers 内容
其他两个表也同样有数据。
持久化成功。
四.三 移除 JobDetail 和 Trigger的配置
因为将 JobDetail 和 Trigger的信息,已经持久化到数据库里面了, 那么就可以将它的配置进行移除了(通常是不移除的,
这儿只是演示一下持久化)。
只保留 Scheduler 的配置
<!-- 配置 scheduler 调度器 -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 没有触发器了,所以将触发器 triggers 属性也删除 -->
<!-- 引入 quartz的配置信息 -->
<!-- <property name="configLocation" value="classpath:quartz.properties"></property> -->
<property name="quartzProperties">
<value>
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
<!-- org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore -->
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
<!--驱动-->
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
<!-- 数据库表前缀 -->
org.quartz.jobStore.tablePrefix:qrtz_
</value>
</property>
<!-- 配置数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
这个时候,重启服务器,
仍然可以正常的运行。
通过数据库持久化,可以做定时任务管理系统。
五. Quartz 持久化的扩展
将 JobDetail,Trigger 存储到数据库里面,就可以完成持久化, 在项目运行的过程中,如果将合法的数据,
插入到对应的数据库表里面,是否就可以创建任务呢, 作一个任务管理系统的模块呢? 是可以的。
Quartz 支持动态的添加任务。
五.一 编写动态任务 MyJob2
package com.yjl.job;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class MyJob2 extends QuartzJobBean implements Serializable{
private static final long serialVersionUID = 1L;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
//要做的事,是打印当前的时间
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//格式化时间
String dateString=sdf.format(new Date());
System.out.println("动态任务,备份数据库的时间是:"+dateString);
}
}
类完整路径为: com.yjl.job.MyJob2
五.二 构建JobAndTrigge 的实体Bean JobAndTrigger
创建一个 JobAndTrigger的Bean, 里面封装一些 Job和Trigger的对象信息, 这些对象信息是前端传递过来的。
package com.yjl.trigger;
import java.io.Serializable;
/**
*
* @author 两个蝴蝶飞
*
*用于接收 配置任务和触发器的信息
*/
public class JobAndTrigger implements Serializable{
private static final long serialVersionUID = 1L;
/**
* @param jobName 任务名称
* @param jobGroupName 任务组的名称
* @param jobClassName 任务的名称
* @param triggerName 触发器名称
* @param triggerGroupName 触发器组名称
* @param cronExpression cron表达式
* @param repeatInterval 间隔
* @param repeatCount 次数
* @param startDelay 延迟开始时间
*/
private String jobName;
private String jobGroupName;
private String jobClassName;
private String triggerName;
private String triggerGroupName;
private String cronExpression;
private Long repeatInterval;
private Integer repeatCount;
private Long startDelay;
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getJobGroupName() {
return jobGroupName;
}
public void setJobGroupName(String jobGroupName) {
this.jobGroupName = jobGroupName;
}
public String getJobClassName() {
return jobClassName;
}
public void setJobClassName(String jobClassName) {
this.jobClassName = jobClassName;
}
public String getTriggerName() {
return triggerName;
}
public void setTriggerName(String triggerName) {
this.triggerName = triggerName;
}
public String getTriggerGroupName() {
return triggerGroupName;
}
public void setTriggerGroupName(String triggerGroupName) {
this.triggerGroupName = triggerGroupName;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public Long getRepeatInterval() {
return repeatInterval;
}
public void setRepeatInterval(Long repeatInterval) {
this.repeatInterval = repeatInterval;
}
public Integer getRepeatCount() {
return repeatCount;
}
public void setRepeatCount(Integer repeatCount) {
this.repeatCount = repeatCount;
}
public Long getStartDelay() {
return startDelay;
}
public void setStartDelay(Long startDelay) {
this.startDelay = startDelay;
}
@Override
public String toString() {
return "JobAndTrigger [jobName=" + jobName + ", jobGroupName=" + jobGroupName + ", jobClassName=" + jobClassName
+ ", triggerName=" + triggerName + ", triggerGroupName=" + triggerGroupName + ", cronExpression="
+ cronExpression + ", repeatInterval=" + repeatInterval + ", repeatCount=" + repeatCount
+ ", startDelay=" + startDelay + "]";
}
}
五.三 编写 Action QuartzAction
/**
*
* @author 两个蝴蝶飞
*
* 任务管理的控制器
*
*/
@Controller
@RequestMapping("/Quartz")
public class QuartzAction {
//Scheduler 是注入的
@Autowired
private Scheduler scheduler;
//查看列表
@RequestMapping("/list")
@ResponseBody
public Map<String,Object> list(){
Map<String,Object> map=new HashMap<String,Object>();
map.put("data",null);
return map;
}
//只演示一下添加操作
@RequestMapping("/add")
@ResponseBody
public Map<String,Object> add(JobAndTrigger jobAndTrigger) throws Exception{
Map<String,Object> map=new HashMap<String,Object>();
//创建JobDetail
JobDetail jobDetail=JobBuilder
.newJob((Class<? extends Job>) Class.forName(jobAndTrigger.getJobClassName()))
.withIdentity(jobAndTrigger.getJobName(),jobAndTrigger.getJobGroupName())
.storeDurably(true)
.build();
//创建Trigger
Trigger trigger=TriggerBuilder.newTrigger()
.withIdentity(jobAndTrigger.getTriggerName(),jobAndTrigger.getTriggerGroupName())
.withSchedule(CronScheduleBuilder.cronSchedule(jobAndTrigger.getCronExpression()))
.build();
//关联起来
scheduler.scheduleJob(jobDetail, trigger);
map.put("response_status",true);
return map;
}
}
五.四 applicationContext-job.xml 配置
与 四.三 移除后的配置一致, 不重复复制了。
五.五 编写前端页面 index.jsp
直接放置到 index.jsp 页面里面了, 引入 bootstrap 来美化样式。
构建一个简单的 Cron 触发器。
<body>
<div class="col-sm-6 col-sm-offset-3">
<div class="col-sm-offset-2" style="color:#D33;margin-top:30px;">
<h2>两个蝴蝶飞 定时任务添加</h2>
</div>
<div style="margin-top:40px;">
<form action="${pageContext.request.contextPath}/Quartz/add" method="post"
class="form-horizontal" role="form">
<div class="form-group">
<label class="col-md-2 control-label">任务名称:</label>
<div class="col-md-4">
<input type="text" class="form-control"
name="jobName" value=""/>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">任务组名称:</label>
<div class="col-md-4">
<input type="text" class="form-control"
name="jobGroupName" value=""/>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">任务类路径:</label>
<div class="col-md-4">
<input type="text" class="form-control"
name="jobClassName" value=""/>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">触发器名称:</label>
<div class="col-md-4">
<input type="text" class="form-control"
name="triggerName" value=""/>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">触发器组名称:</label>
<div class="col-md-4">
<input type="text" class="form-control"
name="triggerGroupName" value=""/>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">cron表达式:</label>
<div class="col-md-4">
<input type="text" class="form-control"
name="cronExpression" value=""/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3">
<input type="submit" value="添加任务" class="btn btn-success"/>
</div>
</div>
</form>
</div>
</div>
</body>
五.六 重启服务器验证
输入网址: http://localhost:8080/Quartz_Persistence
填写相应的信息:
在点击之前,看一下控制台的任务执行:
全部都是 Spring 的。
点击 添加任务按钮,
查看一下控制台:
页面跳转
数据库信息 qrtz_cron_triggers 内容查看
关闭服务器后,重新开启
可以动态地进行添加任务,当然,也可以进行移除任务,挂起任务,修改任务的触发cron表达等。
老蝴蝶这儿就不做过多的讲解了。
本章节代码链接为:
链接:https://pan.baidu.com/s/19S3PsZkHn_5t3SPRkK_68Q
提取码:5o4u
谢谢您的观看!!!