Quartz的持久化数据库(九)

勿以恶小而为之,勿以善小而不为--------------------------刘备
劝诸君,多行善事积福报,莫作恶

上一章简单介绍了 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 

谢谢您的观看!!!
  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
### 回答1: Quartz是一种广泛使用的开源调度器,可用于安排和执行重复的任务。它可以持久化数据库中以保证调度任务持久化和可靠性。 要将Quartz持久化数据库中,需要配置Quartz的数据存储设置。具体步骤如下: 1. 首先,需要在项目中添加Quartz的相关依赖库。 2. 然后,在Quartz的配置文件中指定要使用的数据存储方式。这可以通过设置以下属性来完成: ``` org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.dataSource = myDS org.quartz.jobStore.tablePrefix = QRTZ_ ``` 这些属性指定了使用JDBC JobStore来管理Quartz作业,以及使用指定的数据源和表前缀。 3. 接下来,需要在项目中配置数据源。这可以通过在项目的配置文件中添加以下内容来完成: ``` <bean id="myDS" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost/quartz"/> <property name="username" value="root"/> <property name="password" value=""/> <property name="maxActive" value="100"/> <property name="maxIdle" value="30"/> </bean> ``` 这将建一个基本的数据源,以连接到MySQL数据库,并指定要使用的用户名和密码。 4. 最后,需要在Quartz的配置文件中设置以下属性,以启用持久化: ``` org.quartz.jobStore.isClustered = false org.quartz.jobStore.useProperties = false org.quartz.jobStore.misfireThreshold = 60000 org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate ``` 这些属性将启用持久化,并指定Quartz的一些行为,例如任务执行延迟和驱动程序代理类。 完成上述步骤后,Quartz就会将作业和触发器存储在指定的数据库中,以便在应用程序重新启动时继续执行。 ### 回答2: Quartz是一个开源的任务调度框架,可以实现定时任务的管理和执行。对于需要持久化数据库任务Quartz提供了一种方便的方式来实现。 首先,我们需要建一个数据库表来存储Quartz的相关信息,例如任务名称、任务分组、触发器类型、任务描述、触发器表达式等。可以使用SQL脚本来建这个表,也可以使用Quartz提供的API来自动建。 在Quartz的配置文件中,我们需要指定数据库及相关信息。这个配置文件可以是一个.properties文件或者一个.xml文件。其中,我们需要配置数据库的连接信息,例如数据库的URL、用户名和密码。还需要配置Quartz使用的数据库驱动程序。 在任务调度的代码中,我们可以使用Quartz提供的API来建和管理任务。首先,我们需要建一个Job类来定义要执行的任务。然后,建一个JobDetail对象,并指定要执行的Job类。接下来,建一个触发器(Trigger)对象,并设置触发器的相关属性,例如触发时间、重复次数等。 在Quartz的配置文件中,我们还可以配置任务调度的相关策略,例如任务调度的线程池大小、任务触发器的优先级、任务持久化等。通过设置任务持久化为true,Quartz会将任务的相关信息持久化数据库中。 当我们启动Quartz任务调度器时,Quartz会根据配置的触发器信息,自动调度和执行任务。执行过程中,Quartz会将任务的相关执行信息存储到数据库中。这些信息包括任务的执行时间、执行状态、执行结果等。 通过Quartz持久化功能,我们可以保证即使在应用程序重启或者服务器宕机的情况下,定时任务仍然能够准确地执行。这对于一些重要的定时任务来说非常关键,可以提高系统的可靠性和稳定性。 ### 回答3: Quartz是一个开源的作业调度框架,它允许开发人员在Java应用程序中配置和管理作业的执行。Quartz持久化功能允许将作业和调度信息保存到数据库中,以确保在应用程序重启或故障恢复后作业可以正确地继续执行。 在Quartz持久化过程中,主要涉及到两个核心概念:作业存储和触发器存储。 作业存储是用于存储作业相关信息的数据库表,包括作业名称、作业组、作业类、作业描述等。通过将作业信息存储到数据库中,可以确保即使应用程序停止运行,作业的配置信息仍然可以保留。 触发器存储是用于存储触发器相关信息的数据库表,包括触发器名称、触发器组、触发器类型、触发器运行时间等。通过将触发器信息存储到数据库中,可以确保触发器的调度信息可以被恢复,从而保证作业能够按照预定的时间和频率执行。 Quartz提供了多种数据库持久化方案,包括使用JDBC进行持久化、使用JPA进行持久化等。开发人员可以根据自己的需求选择最适合的方案进行配置。 此外,Quartz还提供了相应的API和工具,使得将作业和触发器信息持久化数据库中变得简单和方便。开发人员可以通过编写代码或者配置文件来实现持久化的相关功能。 总之,Quartz持久化功能可以确保作业和调度信息能够持久保存到数据库中,从而保证在应用程序重启或故障恢复后作业可以正确地继续执行。这样可以提高应用程序的可靠性和稳定性,同时也提供了方便的管理和配置方式。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

两个蝴蝶飞

你的鼓励,是老蝴蝶更努力写作的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值