一、初始化数据库11张quartz表:qrtz_*  

先从官网下载好quartz2.3.0包:http://www.quartz-scheduler.org/downloads/

解压后进入目录:quartz-2.3.0-SNAPSHOT\src\org\quartz\impl\jdbcjobstore

得到22种数据库的11张qrtz_*表的初始化SQL,这里列举几个经典的数据库文件:tables_oracle.sql、tables_mysql_innodb.sql、tables_sqlServer.sql、tables_postgres.sql

二、配置定时器quartz.properties

#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName=TestScheduler
#instance_1 更改后缀数字后,程序可以执行不同ID的调度器,启动多个调度器,有利于观察其中一个实例宕机后,另外实例恢复这个实例的job任务情况
org.quartz.scheduler.instanceId=instance_1 #============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=5
org.quartz.threadPool.threadPriority=5 #============================================================================
# 配置Oracle数据库,命名dataSource为myDS
#============================================================================
# 支持PostgreSQL数据库
#org.quartz.dataSource.myDS.driver=org.postgresql.Driver
#org.quartz.dataSource.myDS.URL=jdbc:postgresql://localhost:5432/quartz
org.quartz.dataSource.myDS.driver=oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.myDS.URL=jdbc:oracle:thin:@localhost:1521:orcl
org.quartz.dataSource.myDS.user=zhuwen
org.quartz.dataSource.myDS.password=ZHUwen12
org.quartz.dataSource.myDS.maxConnections=5
org.quartz.dataSource.myDS.validationQuery=select 0 FROM DUAL #============================================================================
# 配置job任务存储策略,指定一个叫myDS的dataSource
#============================================================================
org.quartz.jobStore.misfireThreshold: 60000
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
# 支持PostgreSQL数据库
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
# 支持Oracle数据库
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.useProperties=false
org.quartz.jobStore.dataSource=myDS
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered=true

三、job任务类

第一个job类:SimpleRecoveryJob

package org.quartz.examples.example13;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.Date; /**
* 一个愚蠢的作业实现,用于单元测试。
*/
public class SimpleRecoveryJob implements Job { private static Logger LOG = LoggerFactory.getLogger(SimpleRecoveryJob.class); private static final String COUNT = "count"; //必须要有public修饰的无参构造函数
public SimpleRecoveryJob() {
} //任务执行方法
public void execute(JobExecutionContext context) throws JobExecutionException { JobKey jobKey = context.getJobDetail().getKey(); // 如果作业正在恢复。如果由于“恢复”情况而重新执行作业,此方法将返回true。
if (context.isRecovering()) {
// LOG.info("恢复作业:SimpleRecoveryJob: " + jobKey + " RECOVERING at " + new Date());
System.err.println("恢复作业:SimpleRecoveryJob: " + jobKey + " RECOVERING at " + new Date());
} else {
// LOG.info("不恢复作业:SimpleRecoveryJob: " + jobKey + " starting at " + new Date());
System.err.println("不恢复作业:SimpleRecoveryJob: " + jobKey + " starting at " + new Date());
} // 睡眠10秒
long delay = 10L * 1000L;
try {
Thread.sleep(delay);
} catch (Exception e) {
//
} JobDataMap data = context.getJobDetail().getJobDataMap();
int count;
if (data.containsKey(COUNT)) {
count = data.getInt(COUNT);
} else {
count = 0;
}
count++;
data.put(COUNT, count); LOG.info("SimpleRecoveryJob: " + jobKey + " done at " + new Date() + "\n Execution #" + count); } }

下面是第二个job类,注意这个job类不允许多线程并发执行:

package org.quartz.examples.example13;

import org.quartz.DisallowConcurrentExecution;
import org.quartz.PersistJobDataAfterExecution; /**
* 这个作业具有与SimpleRecoveryJob相同的功能,只是这个作业实现是“有状态的”,
* 因为它将在每次执行之后自动重新持久化它的数据(JobDataMap),并且一次只能执行JobDetail的一个实例。
*
*/
@PersistJobDataAfterExecution //持久化JobDataMap里的数据,使下一个定时任务还能获取到这些值
@DisallowConcurrentExecution //禁止并发多任务执行,所以永远只有一个任务在执行中
public class SimpleRecoveryStatefulJob extends SimpleRecoveryJob { public SimpleRecoveryStatefulJob() {
super();
}
}

四、任务调度类

package org.quartz.examples.example13;

import static org.quartz.DateBuilder.futureDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger; import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* 用于测试/显示JDBCJobStore (JobStoreTX或JobStoreCMT)的集群特性。
* <p>
* 所有实例必须使用不同的属性文件,因为它们的实例id必须不同,但是所有其他属性应该相同。
* </p>
* <p>
* 如果您希望它清除现有的作业&触发器,设置clearJobs=true
* </p>
* <p>
* 您可能需要先清空残留的表数据,因为将来自非集群设置的数据与集群设置的数据混合在一起可能是不好的。
* </p>
* <p>
* 你可以在运行多个Scheduler实例的时候,杀死其中一个实例,并确保其余实例恢复正在进行的作业。注意,使用默认设置检测故障可能需要15秒左右的时间。
* </p>
* <p>
* 还可以尝试使用/不使用调度程序注册的shutdown-hook插件运行它。(org.quartz.plugins.management.ShutdownHookPlugin)。
* </p>
* <p>
* 注意:从不要在单独的机器上运行集群,除非它们的时钟使用某种形式的时间同步服务(例如NTP守护进程)进行同步。
* </p>
*/
public class ClusterExample { private static Logger LOG = LoggerFactory.getLogger(ClusterExample.class); public void run(boolean inClearJobs, boolean inScheduleJobs) throws Exception { // 初始化调度器
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler(); if (inClearJobs) {
LOG.warn("***** 删除已存在的job任务和triggers触发器。Deleting existing jobs/triggers *****");
sched.clear();
} if (inScheduleJobs) {
LOG.info("------- Scheduling Jobs ------------------");
String schedId = sched.getSchedulerInstanceId(); // ========================================================
// ============ job1
// ========================================================
int count = 1;
JobDetail job = newJob(SimpleRecoveryJob.class).withIdentity("job_" + count, schedId).requestRecovery() // 如果job执行过程中宕机,则job重新执行
.build();
SimpleTrigger trigger = newTrigger().withIdentity("triger_" + count, schedId)
.startAt(futureDate(1, IntervalUnit.SECOND))
.withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInSeconds(5)).build();
LOG.info(job.getKey() + " will run at: " + trigger.getNextFireTime() + " and repeat: "
+ trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds");
sched.scheduleJob(job, trigger); // ========================================================
// ============ job2
// ========================================================
count++;
job = newJob(SimpleRecoveryJob.class).withIdentity("job_" + count, schedId).requestRecovery() // 如果job执行过程中宕机,则job重新执行
.build();
trigger = newTrigger().withIdentity("triger_" + count, schedId).startAt(futureDate(2, IntervalUnit.SECOND))
.withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInSeconds(5)).build();
LOG.info(job.getKey() + " will run at: " + trigger.getNextFireTime() + " and repeat: "
+ trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds");
sched.scheduleJob(job, trigger); // ========================================================
// ============ job3,这里使用的是job子类SimpleRecoveryStatefulJob
// ========================================================
count++;
job = newJob(SimpleRecoveryStatefulJob.class).withIdentity("job_" + count, schedId).requestRecovery() // 如果job执行过程中宕机,则job重新执行
.build();
trigger = newTrigger().withIdentity("triger_" + count, schedId).startAt(futureDate(1, IntervalUnit.SECOND))
.withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInSeconds(3)).build();
LOG.info(job.getKey() + " will run at: " + trigger.getNextFireTime() + " and repeat: "
+ trigger.getRepeatCount() + " times, every " + trigger.getRepeatInterval() / 1000 + " seconds");
sched.scheduleJob(job, trigger); // ========================================================
// ============ job4
// ========================================================
count++;
job = newJob(SimpleRecoveryJob.class).withIdentity("job_" + count, schedId).requestRecovery() // 如果job执行过程中宕机,则job重新执行
.build();
trigger = newTrigger().withIdentity("triger_" + count, schedId).startAt(futureDate(1, IntervalUnit.SECOND))
.withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInSeconds(4)).build();
LOG.info(job.getKey() + " will run at: " + trigger.getNextFireTime() + " & repeat: "
+ trigger.getRepeatCount() + "/" + trigger.getRepeatInterval());
sched.scheduleJob(job, trigger); // ========================================================
// ============ job5
// ========================================================
count++;
job = newJob(SimpleRecoveryJob.class).withIdentity("job_" + count, schedId).requestRecovery() // 如果job执行过程中宕机,则job重新执行
.build();
trigger = newTrigger().withIdentity("triger_" + count, schedId).startAt(futureDate(1, IntervalUnit.SECOND))
.withSchedule(simpleSchedule().withRepeatCount(20).withIntervalInMilliseconds(4500L)).build();
LOG.info(job.getKey() + " will run at: " + trigger.getNextFireTime() + " & repeat: "
+ trigger.getRepeatCount() + "/" + trigger.getRepeatInterval());
sched.scheduleJob(job, trigger);
} sched.start(); LOG.info("------- Waiting for one hour... ----------");
try {
Thread.sleep(3600L * 1000L);
} catch (Exception e) {
//
} sched.shutdown();
LOG.info("------- Shutdown Complete ----------------");
} public static void main(String[] args) throws Exception {
boolean clearJobs = false;
boolean scheduleJobs = true; for (String arg : args) {
if (arg.equalsIgnoreCase("clearJobs")) {
clearJobs = true;
} else if (arg.equalsIgnoreCase("dontScheduleJobs")) {
scheduleJobs = false;
}
} clearJobs = true;
scheduleJobs = true; ClusterExample example = new ClusterExample();
example.run(clearJobs, scheduleJobs);
}
}

quartz2.3.0(十三)数据库持久化定时器job任务和trigger触发器,在多个调度器实例情况下,由其它调度器实例恢复执行调度器宕机的job任务的更多相关文章

  1. kafka producer 打数据,ack 为 0, 1, -1 的时候代表啥, 设置 -1 的时候,什么情况下,leader 会认为一条消息 commit了?

    1(默认)  数据发送到Kafka后,经过leader成功接收消息的的确认,就算是发送成功了.在这种情况下,如果leader宕机了,则会丢失数据. 0 生产者将数据发送出去就不管了,不去等待任何返回. ...

  2. quartz2.3.0系列目录——带您由浅入深全面掌握quartz2.3.0

    quartz2.3.0系列目录 官网下载地址:http://www.quartz-scheduler.org/downloads/ 本系列demo全部来源于官网,仅仅是简化和汉化了注释!一部分代码de ...

  3. quartz2.3.0(十五)执行、暂停、继续执行、清除,花式操作数据库中持久化的job任务

    #################################################################################################### ...

  4. Kafka 0.8 宕机问题排查步骤

    CPU 利用率高的排查方法 看看该机器的连接数是不是比其他机器多,监听的端口数:netstat -anlp | wc -l Kafka-0.8的停止和启动 启动: cd /usr/local/kafk ...

  5. android数据库持久化框架, ormlite框架,

    前言 Android中内置了SQLite,但是对于数据库操作这块,非常的麻烦.其实可以试用第3方的数据库持久化框架对之进行结构上调整, 摆脱了访问数据库操作的细节,不用再去写复杂的SQL语句.虽然这样 ...

  6. Spring+Redis集成+关系型数据库持久化

    本篇文章主要介绍了"Spring+Redis集成+关系型数据库持久化",主要涉及到Spring+Redis集成+关系型数据库持久化方面的内容,对于Spring+Redis集成+关系 ...

  7. quartz2.3.0(十)xml配置方式定义quartz定时任务

    1.新增pom依赖 除了按照<quartz2.3.0系列目录——带您由浅入深全面掌握quartz2.3.0>添加依赖之外,pom.xml里新增加依赖: <dependency> ...

  8. SpringCloud微服务实战——搭建企业级开发框架(五):数据库持久化集成MySql+Druid+MyBatis-Plus

      在引入相关数据库持久化相关依赖库之前,我们可以考虑到,当我们因业务开发需要,引入各种各样的依赖库时,Jar包冲突是我们必须面对的一个问题,Spring为了解决这些Jar包的冲突,推出了各种bom, ...

  9. 删库到跑路?还得看这篇Redis数据库持久化与企业容灾备份恢复实战指南

    本章目录 0x00 数据持久化 1.RDB 方式 2.AOF 方式 如何抉择 RDB OR AOF? 0x01 备份容灾 一.备份 1.手动备份redis数据库 2.迁移Redis指定db-数据库 3 ...

随机推荐

  1. Mac下删除自己安装的Python

    删除Python框架sudo rm -rf /Library/Frameworks/Python.framework/Versions/x.x 删除Python程序sudo rm -rf “/Appl ...

  2. 暂时性死区TDZ理解与总结

    为什么会出现暂时性死区? 先来看看 ES6 标准中对 let/const 声明中的解释 第13章,有如下一段文字:The variables are created when their contai ...

  3. JVM内存的划分

    JVM内存的划分有五片: 1.   寄存器: 2.   本地方法区: 3.   方法区: 4.   栈内存: 5.   堆内存.

  4. C++2.0新特性(七)——<Smart Pointer(智能指针)之weak_ptr>

    一.weak_ptr出现的意义 上一节提到过shared_ptr,它会自动释放“不再需要使用的对象”的相应的资源,但是它不是万能的,在某些时候(比如说循环引用),它会显得力不从心,这就是weak_pt ...

  5. 测试linux下磁盘的读写速率

    1) 通过df -h命令查看磁盘情况 Filesystem            Size  Used Avail Use% Mounted on/dev/sda4             289G  ...

  6. ACR Code Pacs

    ACR Index for Radiological Diagnosis 简称ACR Index,ACR Key或ACR Code,是一种应用于影像学分类的病理编码,由美国放射学院(American ...

  7. meta name="location" 标签的使用

    在进行一些操作的时候,我们可能会用到这个标签来什么,地理位置,不错的网站优化标签. <meta name="location" content="province= ...

  8. CNeo编程语言概述

    C语言诞生于1970年,当时在AT&T实验室由Dennis Ritchie主导开发的.据说当时仅用了一周的时间就做好了C语言编译器,所以尽管C语言从90年正式纳入ISO标准委员会,其编号为IS ...

  9. python路径相关技巧

    在文件C:\work\python\rqalpha\rqalpha\utils\config.py 找文件:C:\work\python\rqalpha\rqalpha\config.yml 则通过下 ...

  10. (转)IIS windows认证

    转自 https://my.oschina.net/u/2551141/blog/2878673 IIS配置Windows认证方式: 1.IIS->>要设置的网站->>身份验证 ...