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

前提准备:

先在数据库中建立quartz需要的11张表(我这里用的是Oracle数据库),根据不同的数据库quartz分别提供了不同的初始化sql文件,sql文件路径在 quartz-2.3.0-SNAPSHOT-0724\src\org\quartz\impl\jdbcjobstore下:

ScheduleBuilder是trigger触发器的触发规则定制类,旗下有4种触发器实现类:  CalendarIntervalScheduleBuilder、CronScheduleBuilder、DailyTimeIntervalScheduleBuilder、SimpleScheduleBuilder。

#############################################################################################################################################

        1、 11张表不同定时方式分别存储了不同数据到不同的表

这里演示了CronScheduleBuilder和SimpleScheduleBuilder两种定时方式,分别执行后面的StoreSimpleTrigger2OracleExample.java 和 StoreCronTrigger2OracleExample.java 就能看到数据库如下的差别:

#############################################################################################################################################

这4中实现类在数据库的11张表中存储一个任务时,分别会产生不一样的数据,用颜色标注insert语句如下:

select * from qrtz_blob_triggers;   --没有insert语句就表示此表一直没有数据

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_calendars;
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_cron_triggers;

Insert into QRTZ_CRON_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,CRON_EXPRESSION,TIME_ZONE_ID)
values (‘SchedulerJoyce0725‘,‘cronTrigger‘,‘cronGroup1‘,‘0/5 * * * * ?‘,‘Asia/Shanghai‘);

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_fired_triggers;
Insert into QRTZ_FIRED_TRIGGERS (SCHED_NAME,ENTRY_ID,TRIGGER_NAME,TRIGGER_GROUP,INSTANCE_NAME,FIRED_TIME,SCHED_TIME,PRIORITY,STATE,JOB_NAME,JOB_GROUP,IS_NONCONCURRENT,REQUESTS_RECOVERY)
values (‘SchedulerJoyce0725‘,‘InstanceJoyce07251564061848994‘,‘cronTrigger‘,‘cronGroup1‘,‘InstanceJoyce0725‘,1564061855002,1564061855000,5,‘EXECUTING‘,‘simpleRecoveryJob‘,‘cronGroup1‘,‘0‘,‘0‘);  --每一次远程启动时ENTRY_ID总是会变一变

Insert into QRTZ_FIRED_TRIGGERS (SCHED_NAME,ENTRY_ID,TRIGGER_NAME,TRIGGER_GROUP,INSTANCE_NAME,FIRED_TIME,SCHED_TIME,PRIORITY,STATE,JOB_NAME,JOB_GROUP,IS_NONCONCURRENT,REQUESTS_RECOVERY) values (‘SchedulerJoyce0725‘,‘InstanceJoyce07251564066439267‘,‘simpleTriger1‘,‘simpleGroup‘,‘InstanceJoyce0725‘,1564066446293,1564066451270,5,‘ACQUIRED‘,null,null,‘0‘,‘0‘);

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_job_details;
Insert into QRTZ_JOB_DETAILS (SCHED_NAME,JOB_NAME,JOB_GROUP,DESCRIPTION,JOB_CLASS_NAME,IS_DURABLE,IS_NONCONCURRENT,IS_UPDATE_DATA,REQUESTS_RECOVERY,JOB_DATA)
values (‘SchedulerJoyce0725‘,‘simpleRecoveryJob‘,‘cronGroup1‘,null,‘org.quartz.examples.example15.SimpleRecoveryJob‘,‘0‘,‘0‘,‘0‘,‘0‘,
TO_BLOB(HEXTORAW(‘...‘))|| TO_BLOB(HEXTORAW(‘...‘)));

Insert into QRTZ_JOB_DETAILS (SCHED_NAME,JOB_NAME,JOB_GROUP,DESCRIPTION,JOB_CLASS_NAME,IS_DURABLE,IS_NONCONCURRENT,IS_UPDATE_DATA,REQUESTS_RECOVERY,JOB_DATA)
values (‘SchedulerJoyce0725‘,‘simpleJob1‘,‘simpleGroup‘,null,‘org.quartz.examples.example15.SimpleRecoveryJob‘,‘0‘,‘0‘,‘0‘,‘1‘,
TO_BLOB(HEXTORAW(‘...‘))|| TO_BLOB(HEXTORAW(‘...‘)));

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_locks;
Insert into qrtz_locks (SCHED_NAME,LOCK_NAME) values (‘SchedulerJoyce0725‘,‘STATE_ACCESS‘);
Insert into qrtz_locks (SCHED_NAME,LOCK_NAME) values (‘SchedulerJoyce0725‘,‘TRIGGER_ACCESS‘);

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_paused_trigger_grps;

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_scheduler_state;
Insert into qrtz_scheduler_state (SCHED_NAME,INSTANCE_NAME,LAST_CHECKIN_TIME,CHECKIN_INTERVAL)
values (‘SchedulerJoyce0725‘,‘InstanceJoyce0725‘,1564061857522,7500);

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_simple_triggers;

Insert into QRTZ_SIMPLE_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,REPEAT_COUNT,REPEAT_INTERVAL,TIMES_TRIGGERED)

values (‘SchedulerJoyce0725‘,‘simpleTriger1‘,‘simpleGroup‘,20,5000,2);

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
select * from qrtz_simprop_triggers;

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

select * from qrtz_triggers;
Insert into qrtz_triggers (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,JOB_NAME,JOB_GROUP,DESCRIPTION,NEXT_FIRE_TIME,PREV_FIRE_TIME,PRIORITY,TRIGGER_STATE,TRIGGER_TYPE,START_TIME,END_TIME,CALENDAR_NAME,MISFIRE_INSTR,JOB_DATA)
values (‘SchedulerJoyce0725‘,‘cronTrigger‘,‘cronGroup1‘,‘simpleRecoveryJob‘,‘cronGroup1‘,null,1564061865000,1564061860000,5,‘ACQUIRED‘,‘CRON‘,1564061849000,0,null,0, EMPTY_BLOB());

Insert into QRTZ_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,JOB_NAME,JOB_GROUP,DESCRIPTION,NEXT_FIRE_TIME,PREV_FIRE_TIME,PRIORITY,TRIGGER_STATE,TRIGGER_TYPE,START_TIME,END_TIME,CALENDAR_NAME,MISFIRE_INSTR,JOB_DATA) values (‘SchedulerJoyce0725‘,‘simpleTriger1‘,‘simpleGroup‘,‘simpleJob1‘,‘simpleGroup‘,null,1564066451270,1564066446270,5,‘ACQUIRED‘,‘SIMPLE‘,1564066441270,0,null,0, EMPTY_BLOB());

#############################################################################################################################################

    2、  job任务类,SimpleRecoveryJob.java

#############################################################################################################################################

package org.quartz.examples.example15;

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;

/**
 * 一个job作业。
 */
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());
        } else {
            LOG.info("不恢复作业:SimpleRecoveryJob: " + jobKey + " starting at " + new Date());
        }

        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);

    }

}

#############################################################################################################################################

    3、  简单定时任务存储到数据库表,StoreSimpleTrigger2OracleExample.java

#############################################################################################################################################

package org.quartz.examples.example15;

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;

/**
 * 简单定时任务存储到数据库表。
 * 存储job任务到数据库,这里打印的job任务都是:     不恢复作业……
 */
public class StoreSimpleTrigger2OracleExample {

    private static Logger LOG = LoggerFactory.getLogger(StoreSimpleTrigger2OracleExample.class);

    public void run(boolean inClearJobs, boolean inScheduleJobs) throws Exception {

        // 初始化调度器
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler sched = sf.getScheduler();

        if (inClearJobs) {
            sched.clear();
            LOG.warn("***** Deleted existing jobs/triggers *****");
        }

        LOG.info("------- Initialization Complete -----------");

        if (inScheduleJobs) {

            LOG.info("------- Scheduling Jobs ------------------");

            String schedId = sched.getSchedulerInstanceId();

            // ========================================================
            // ============ job1
            // ========================================================
            int count = 1;
            JobDetail job = newJob(SimpleRecoveryJob.class).withIdentity("simpleJob" + count, "simpleGroup").requestRecovery() // 如果job执行过程中宕机,则job重新执行
                    .build();
            SimpleTrigger trigger = newTrigger().withIdentity("simpleTriger" + count, "simpleGroup")
                    .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("job0724_" + count, schedId).requestRecovery() // 如果job执行过程中宕机,则job重新执行
//                    .build();
//            trigger = newTrigger().withIdentity("triger0724_" + 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);

        }

        LOG.info("------- Starting Scheduler ---------------");
        sched.start();
        try {
            Thread.sleep(3600L * 1000L);
        } catch (Exception e) {
            //
        }
        sched.shutdown();
        LOG.info("------- Shutdown Complete ----------------");
    }

    public static void main(String[] args) throws Exception {
        boolean clearJobs = true; // 是否清空job任务
        boolean scheduleJobs = true; // 是否调度任务

        for (String arg : args) {
            if (arg.equalsIgnoreCase("clearJobs")) {
                clearJobs = true;
            } else if (arg.equalsIgnoreCase("dontScheduleJobs")) {
                scheduleJobs = false;
            }
        }

        StoreSimpleTrigger2OracleExample example = new StoreSimpleTrigger2OracleExample();
        example.run(clearJobs, scheduleJobs);
    }
}

#############################################################################################################################################

    4、  cron定义定时任务存储到数据库表,StoreCronTrigger2OracleExample.java

#############################################################################################################################################

package org.quartz.examples.example15;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

import java.util.Date;

import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * cron定义定时任务存储到数据库表。
 * 存储job任务到数据库,这里打印的job任务都是:     不恢复作业……
 */
public class StoreCronTrigger2OracleExample {

    private static Logger LOG = LoggerFactory.getLogger(StoreCronTrigger2OracleExample.class);

    public void run(boolean inClearJobs) throws Exception {

        // 初始化调度器
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler sched = sf.getScheduler();

        if (inClearJobs) {
            sched.clear();
            LOG.warn("***** Deleted existing jobs/triggers *****");
        }

        // ========================================================
        // ============ job1 每20秒执行一次,无限期重复
        // ========================================================
        JobDetail job = newJob(SimpleRecoveryJob.class).withIdentity("simpleRecoveryJob_Recovery", "cronGroup2")
                .requestRecovery() //如果job任务所在服务宕机了或由于其它原因job任务被中断,请标记JobExecutionContext.isRecovering()=true。
                                   //让我可以拿这个标记知道怎么去适配业务场景。
                                   //但是只有恢复任务后首次执行任务时,拿到Recovering标记值为true,此后该任务Recovering值又标记为了false。
                .build();
        //每5秒执行一次
        CronTrigger trigger = newTrigger().withIdentity("cronTrigger_Recovery", "cronGroup2").withSchedule(cronSchedule("0/5 * * * * ?")).build();
        Date ft = sched.scheduleJob(job, trigger);
        LOG.info(job.getKey() + " has been scheduled to run at: " + ft + " and repeat based on expression: "
                + trigger.getCronExpression());

        LOG.info("------- Starting Scheduler ---------------");
        sched.start();
        try {
            Thread.sleep(3600L * 1000L);
        } catch (Exception e) {
            //
        }

        // 暂停执行任务
        sched.pauseJob(job.getKey());
        LOG.info("调度器暂停执行定时器,主线程睡眠11秒!!!!会错过执行job1的N次定时任务。模拟当定时器的执行线程由于抢不到CPU时间或其他事件错过执行的情况。");
        Thread.sleep(11L * 1000L);
        // 继续执行任务
        sched.resumeJob(job.getKey()); //当定时器得到继续执行的命令时,被错过执行的任务次数,就会按照misfire的定义去执行

        sched.shutdown();
        LOG.info("------- Shutdown Complete ----------------");
    }

    public static void main(String[] args) throws Exception {
        boolean clearJobs = false; // 是否清空job任务

        StoreCronTrigger2OracleExample example = new StoreCronTrigger2OracleExample();
        example.run(clearJobs);
    }
}

#############################################################################################################################################

    5、  执行数据库中的定时任务,RunOracleExistingJobExample.java

#############################################################################################################################################

package org.quartz.examples.example15;

import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 先运行ClusterExample.java,确定Oracle数据库中已存在job任务.
 * 这里打印的job任务都是从数据库表里恢复回来的,所以这些任务的第一次执行会打印:     恢复作业……
 * 此后job任务就只打印:不恢复作业……
 */
public class RunOracleExistingJobExample {

    private static Logger LOG = LoggerFactory.getLogger(RunOracleExistingJobExample.class);

    public void run(boolean inClearJobs) throws Exception {

        // 初始化调度器
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler sched = sf.getScheduler();

        if (inClearJobs) {
            sched.clear();
            LOG.warn("***** Deleted existing jobs/triggers *****");
        }

        LOG.info("------- Starting Scheduler ---------------");
        sched.start();
        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; // 是否清空job任务,这里为不清空

        RunOracleExistingJobExample example = new RunOracleExistingJobExample();
        example.run(clearJobs);
    }
}

原文地址:https://www.cnblogs.com/zhuwenjoyce/p/11247634.html

时间: 2024-12-18 15:11:32

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

从零开始学ios开发(十五):Navigation Controllers and Table Views(中)

这篇内容我们继续上一篇的例子接着做下去,为其再添加3个table view的例子,有了之前的基础,学习下面的例子会变得很简单,很多东西都是举一反三,稍稍有些不同的内容,好了,闲话少说,开始这次的学习. 如果没有上一篇的代码,可以从这里下载Nav_1 1)第三个subtableview:Controls on Table Rows这个例子,我们将为每个table view的每一行添加一个按钮,这个按钮将放在accessory icon的位置(之前我们使用过accessoryType,其实这也是一个

边记边学PHP-(十六)PHP使用MySQL扩展库操作数据库

PHP提供了很多扩展库,这里说的是使用MySQL扩展库,但是这种扩展库在不久的将来就会被摒弃,因为如果使用MySQL扩展库编写的代码在运行的时候会有warning的提示.我本来想直接写另一种,但是感觉这是基础.MySQL扩展库,一说到库,自然而然就想到是一堆函数,很多函数组成一个库,使用扩展库也就是使用里面的函数.MySQL扩展库是完全面向过程的,显然不符合面向对象的特性,被摒弃也是可以理解的.废话不多说,直接上重点. 一.PHP使用MySQL扩展库操作数据库的示意图 此图是我自己画的,可能有不

孤荷凌寒自学python第五十二天初次尝试使用python读取Firebase数据库中记录

(完整学习过程屏幕记录视频地址在文末) 今天继续研究Firebase数据库,利用google免费提供的这个数据库服务,今天主要尝试使用firebase_admin模块来连接firebase数据库. 获得成功. 一.简单总结下今天对firebase_admin模块对象的学习 (一)要通过firebase_admin模块连接到firebase数据库,那么必须要拥有一个从firebase网站上自己的数据库的[用户和权限]处设置的'连接私钥'等相关信息的一个json文件,并下载到项目文件夹中来. (二)

quartz2.3.0(五)制定错过执行任务的misfire策略

感谢兄台: <quartz-misfire 错失.补偿执行> misfire定义 misfire:被错过的执行任务策略 misfire重现——CronTrigger job任务类: package org.quartz.examples.example5; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.Jo

关于大型网站技术演进的思考(十五)--网站静态化处理—前后端分离—中(7)

上篇里我讲到了一种前后端分离方案,这套方案放到服务端开发人员面前比放在web前端开发人员面前或许得到的掌声会更多,我想很多资深前端工程师看到这样的技术方案可能会有种说不出来的矛盾心情,当我的工作逐渐走向越来越专业化的前端开发后,我就时常被这套前后端分离方案所困惑,最近我终于明白了这个困惑的本源在哪里了,那就是这套前后端分离方案其实是服务端驱动的前后端分离方案,它的实现手段又是从服务端的MVC架构体系演化而来,因此该方案最大的问题就是它并没有从根本上改变web前端从属于服务端的被动局面.那么问题来

第十五周oj刷题—— Problem C: 矩形类中运算符重载【C++】

Description 定义一个矩形类,数据成员包括左下角和右上角坐标,定义的成员函数包括必要的构造函数.输入坐标的函数,实现矩形加法,以及计算并输出矩形面积的函数.要求使用提示中给出的测试函数并不得改动. 两个矩形相加的规则是:决定矩形的对应坐标分别相加,如 左下角(1,2),右上角(3,4)的矩形,与 左下角(2,3),右上角(4,5)的矩形相加,得到的矩形是 左下角(3,5),右上角(7,9)的矩形. 这个规则没有几何意义,就这么定义好了. 输出面积的功能通过重载"<<&quo

C#+arcengine10.0+SP5实现鹰眼(加载的是mdb数据库中的数据)

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.esriSystem; using ES

十五周 项目1 工资数据的输入

/* 输入员工工资1000-10000之间,并按从大到小输出*/ #include <iostream> using namespace std; int main( ) { double salarys[500]; int n=0; double t; while(cin>>salarys[n]) { n++; //从cin流读取数据 } //将n名职工的工资排序后输出 for(int i=0; i<n; i++) for(int j=0; j<n-1; j++) {

Redis源码解析(十五)--- aof-append only file解析

继续学习redis源码下的Data数据相关文件的代码分析,今天我看的是一个叫aof的文件,这个字母是append ONLY file的简称,意味只进行追加文件操作.这里的文件追加记录时为了记录数据操作的改变记录,用以异常情况的数据恢复的.类似于之前我说的redo,undo日志的作用.我们都知道,redis作为一个内存数据库,数据的每次操作改变是先放在内存中,等到内存数据满了,在刷新到磁盘文件中,达到持久化的目的.所以aof的操作模式,也是采用了这样的方式.这里引入了一个block块的概念,其实就