Quartz 定时任务使用

官方文档

1. 使用quartz

在开始使用scheduler前,首先使用SchedulerFactory创建一个

SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();

  Scheduler sched = schedFact.getScheduler();

  sched.start();

  // define the job and tie it to our HelloJob class
  JobDetail job = newJob(HelloJob.class)
      .withIdentity("myJob", "group1")
      .build();

  // Trigger the job to run now, and then every 40 seconds
  Trigger trigger = newTrigger()
      .withIdentity("myTrigger", "group1")
      .startNow()
      .withSchedule(simpleSchedule()
          .withIntervalInSeconds(40)
          .repeatForever())
      .build();

  // Tell quartz to schedule the job using our trigger
  sched.scheduleJob(job, trigger);

2. Quartz Api jobs 和 trigger

2.1 Quartz Api
  • [x] Scheduler
  • [x] Job
  • [x] JobDetail
  • [x] Trigger
  • [x] JobBuilder
  • [x] TiggerBuilder

JobBuilder

TriggerBuilder

SimpleScheduleBulder

import static org.quartz.JobBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.CalendarIntervalScheduleBuilder.*;
import static org.quartz.TriggerBuilder.*;
import static org.quartz.DateBuilder.*;

不同的ScheduleBuilder类有自己的方法定义schedules类型

比如DateBuilder类包含各种易于构造java.util的方法。指定时间点的日期实例

2.2 Jobs and triggers
job interface

一个Job需要实现job 接口

package org.quartz;

  public interface Job {

    public void execute(JobExecutionContext context)
      throws JobExecutionException;
  }

当job的trigger触发时,execute(..)方法被==scheduler’s==的一个工作线程执行。JobExecutionContext内含有job的运行信息:执行它的Scheduler,触发它的Trigger,JobDetail 和其他一些items。

JobDetail对象是由Quartz客户机(您的程序)在将作业添加到调度器时创建的。它包含作业的各种属性设置,以及JobDataMap,可用于存储作业类的给定实例的状态信息。它本质上是作业实例的定义,并将在下一课中进一步详细讨论。

触发器对象用于触发作业的执行(或“触发”)。当您希望调度作业时,您将实例化触发器并“优化”其属性,以提供您希望的调度。触发器也可能与JobDataMap关联——这对于将参数传递给特定于触发器触发的作业非常有用。Quartz附带了一些不同的触发器类型,但是最常用的类型是SimpleTrigger和CronTrigger。

如果您需要“一次性”执行(在给定的时间点只执行一个作业),或者需要在给定的时间点触发一个作业,并让它重复N次,两次执行之间的延迟为T,那么SimpleTrigger非常有用。如果您希望基于类似日历的时间表进行触发,例如“每个星期五、中午”或“每个月的第10天10:15”,CronTrigger非常有用。

为什么是工作和触发器?许多作业调度程序没有作业和触发器的独立概念。有些人将“作业”简单地定义为执行时间(或调度)和一些小型作业标识符。其他的类似于Quartz的工作和触发器对象的结合。在开发Quartz时,我们认为在计划和按照计划执行的工作之间创建一个分离是有意义的。这(在我们看来)有许多好处。

例如,作业可以独立于触发器创建和存储在作业调度器中,而且许多触发器可以与相同的作业关联。这种松散耦合的另一个好处是,可以配置在相关触发器过期后仍然保留在调度器中的作业,以便以后可以重新调度它们,而不必重新定义它们。它还允许您修改或替换触发器,而不必重新定义其关联的作业。

2.3 Identities

3. more about job and trigger

使用jobbuilder

import static org.quartz.JobBuilder.*;

上一章节我们简单的定义了一个job

// define the job and tie it to our HelloJob class
  JobDetail job = newJob(HelloJob.class)
      .withIdentity("myJob", "group1") // name "myJob", group "group1"
      .build();

  // Trigger the job to run now, and then every 40 seconds
  Trigger trigger = newTrigger()
      .withIdentity("myTrigger", "group1")
      .startNow()
      .withSchedule(simpleSchedule()
          .withIntervalInSeconds(40)
          .repeatForever())            
      .build();

  // Tell quartz to schedule the job using our trigger
  sched.scheduleJob(job, trigger);

来看一下HelloJob的定义

 public class HelloJob implements Job {

    public HelloJob() {
    }

    public void execute(JobExecutionContext context)
      throws JobExecutionException
    {
      System.err.println("Hello!  HelloJob is executing.");
    }
  }

3.1 JobDataMap

JobDataMap 可以用来存储任意大小的数据,(在数据库中存储为Blob格式的数据类型),实现了java map并添加了常用的方法来存储和检索原始类型数据。

// define the job and tie it to our DumbJob class
  JobDetail job = newJob(DumbJob.class)
      .withIdentity("myJob", "group1") // name "myJob", group "group1"
      .usingJobData("jobSays", "Hello World!")
      .usingJobData("myFloatValue", 3.141f)
      .build();

在job执行期间取出jobDataMap中的数据

public class DumbJob implements Job {

    public DumbJob() {
    }

    public void execute(JobExecutionContext context)
      throws JobExecutionException
    {
      JobKey key = context.getJobDetail().getKey();

      JobDataMap dataMap = context.getJobDetail().getJobDataMap();

      String jobSays = dataMap.getString("jobSays");
      float myFloatValue = dataMap.getFloat("myFloatValue");

      System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
    }
  }

JobExecutionContext’s取出merged后的jobDataMap

public class DumbJob implements Job {

    public DumbJob() {
    }

    public void execute(JobExecutionContext context)
      throws JobExecutionException
    {
      JobKey key = context.getJobDetail().getKey();

      JobDataMap dataMap = context.getMergedJobDataMap();  // Note the difference from the previous example

      String jobSays = dataMap.getString("jobSays");
      float myFloatValue = dataMap.getFloat("myFloatValue");
      ArrayList state = (ArrayList)dataMap.get("myStateData");
      state.add(new Date());

      System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
    }
  }
3.2 Job State and Concurrency
  • [x] @DisallowConcurrentExecution
  • [x] @PersistJobDataAfterExecution
3.3 Other Attributes Of Jobs
  • [x] Durability
  • [x] RequestsRecovery
3.4 JobExecutionException

4. More about Triggers

4.1 Common Trigger Attributes
  • [x] jobKey 标示身份
  • [x] startTime:表明trigger什么时候开始起作用,对于一些类型的trigger来说,startTime到了就会执行;而有一些只是简单表明了什么时间点开始schedule,比如您可以在1月份存储一个带有时间表的触发器,例如“每个月的第5天”,如果startTime属性设置为4月1日,那么在第一次触发之前还有几个月的时间,明白了吧。
  • [x] endTime:表明任务执行的截止日期,举个栗子:一个带有“每个月的第5天”和7月1日结束时间的触发器将在6月5日最后一次触发。
4.2 Priority
.withPriority(int triggerPriority)

有时,项目中可能有许多triggers需要执行,而你的Quartz thread pool是有限的,不能保证在同一时间下所有的trigger在执行的时候都能获取到线程资源执行任务,因此有时候设置priority是有必要的,优先级越高的越先获取到线程资源。
priority需要设置为正整数,默认为5

只有在同一时间下,priority参数才有作用,10:11的优先级永远比10:20的高

被恢复的任务的优先级高于origin trigger的

4.3 Misfire Instructions

trigger 可能因为Quartz’s thread pool 没有足够的线程执行trigger或因为scheduler被关闭而错过了它的执行时间

4.4 Calendars

此calender非java.util.Calendar

calendar对于从触发器的触发计划中排除时间块非常有用。例如,您可以创建一个触发器,该触发器在每个工作日上午9:30触发作业,然后添加一个日历,这个日历用来排除了所有业务假期时间块。


package org.quartz;

public interface Calendar {

  public boolean isTimeIncluded(long timeStamp);

  public long getNextIncludedTime(long timeStamp);

}

注意,方法的参数都是毫秒格式的时间戳,意味着日历可以“划分”出一毫秒那么短的时间段;

Quartz的实现类org.quartz.impl下有丰富多样的Calendar

AnnualCalendar 年历

CronCalendar cron 日历

DailyCalendar 每日日历

HolidayCalendar 假日日历

MonthlyCalendar 月历

WeeklyCalendar 周历

日历必须通过addCalendar(..)方法实例化并注册到调度程序。如果您使用HolidayCalendar,在实例化它之后,需要使用它的addExcludedDate(Date Date)方法来剔除指定的时间,举个栗子:

calendar example

HolidayCalendar cal = new HolidayCalendar();
cal.addExcludedDate( someDate );
cal.addExcludedDate( someOtherDate );

sched.addCalendar("myHolidays", cal, false);


Trigger t = newTrigger()
    .withIdentity("myTrigger")
    .forJob("myJob")
    .withSchedule(dailyAtHourAndMinute(9, 30)) // execute job daily at 9:30
    .modifiedByCalendar("myHolidays") // but not on holidays
    .build();

// .. schedule job with trigger

Trigger t2 = newTrigger()
    .withIdentity("myTrigger2")
    .forJob("myJob2")
    .withSchedule(dailyAtHourAndMinute(11, 30)) // execute job daily at 11:30
    .modifiedByCalendar("myHolidays") // but not on holidays
    .build();

// .. schedule job with trigger2

5. SimpleTrigger

如果需要在特定的时间点精确执行job一次,或者在特定的时间点执行job,然后在特定的时间间隔内重复执行job,==使用simpleTrigger==比如,你想让trigger在2015年1月13日上午11:23:54准时fire,或者你想让它在那个时间fire,然后每十秒钟再fire五次。

然后你会发现==simpleTrigger==主要有==startTime==,==endTime==,==repeat count==,==repeat interval==这几个属性

repeat count 可为0,或正整数,或==SimpleTrigger.REPEAT_INDEFINITELY==

repeat interval 必须大于等于0,为0可能导致重复触发

==Quartz’s DateBuilder==便于创建tigger 的fire时间(在startTime和endTime内)

如果指定了endtime tigger会在startTime和endTime区间内重复执行job,这样你可以自定在此区间内执行次数为==REPEAT_INDEFINITELY==或者设置一个比较大的执行次数(远远超出endtime到来所能够的执行次数)

使用TriggerBuilder构建simpleTrigger


import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.DateBuilder.*:
5.1 指定时间点执行一次
SimpleTrigger trigger = (SimpleTrigger) newTrigger()
    .withIdentity("trigger1", "group1")
    .startAt(myStartTime) // some Date
    .forJob("job1", "group1") // identify job with name, group strings
    .build();
5.2 指定时间点开始执行,然后没10秒钟执行一次,共执行10次
trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .startAt(myTimeToStartFiring)  // if a start time is not given (if this line were omitted), "now" is implied
    .withSchedule(simpleSchedule()
        .withIntervalInSeconds(10)
        .withRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
    .forJob(myJob) // identify job with handle to its JobDetail itself                   
    .build();
5.3 未来5分钟执行一次
trigger = (SimpleTrigger) newTrigger()
    .withIdentity("trigger5", "group1")
    .startAt(DateBuilder.futureDate(5, IntervalUnit.MINUTE)) // use DateBuilder to create a date in the future
    .forJob(myJobKey) // identify job with its JobKey
    .build();
5.4 现在开始执行,每5分钟执行一次一直到22:00点结束执行
  trigger = newTrigger()
    .withIdentity("trigger7", "group1")
    .withSchedule(simpleSchedule()
        .withIntervalInMinutes(5)
        .repeatForever())
    .endAt(dateOf(22, 0, 0))
    .build();
5.5 下个小时开始时开始执行,每2小时执行一次,直到永远
  trigger = newTrigger()
    .withIdentity("trigger8") // because group is not specified, "trigger8" will be in the default group
    .startAt(DateBuilder.evenHourDate(null)) // get the next even-hour (minutes and seconds zero ("00:00"))
    .withSchedule(simpleSchedule()
        .withIntervalInHours(2)
        .repeatForever())
    // note that in this example, 'forJob(..)' is not called
    //  - which is valid if the trigger is passed to the scheduler along with the job  
    .build();

    scheduler.scheduleJob(trigger, job);

花点时间好好熟悉一下==TriggerBuilder==和==SimpleScheduleBuilder==的可用方法

==请注意,TriggerBuilder(和Quartz的其他生成器)通常会为未显式设置的属性选择一个合理的值。如果不调用startAt(..),则假定当前时间(立即)。==

5.6 SimpleTrigger Misfire Instructions

SimpleTrigger有几个指令,可以用来通知Quartz在发生==miessFire==时应该做什么。这些指令被定义为SimpleTrigger本身上的常量

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
MISFIRE_INSTRUCTION_FIRE_NOW
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT

前面的章节已经讲述了所有的trigger都有==Trigger.MISFIRE_INSTRUCTION_SMART_POLICY==这个也是默认值

trigger = newTrigger()
    .withIdentity("trigger7", "group1")
    .withSchedule(simpleSchedule()
        .withIntervalInMinutes(5)
        .repeatForever()
        .withMisfireHandlingInstructionNextWithExistingCount())
    .build();

6. CronTrigger

CronTrigger通常比SimpleTrigger要更有用,如果需要一个基于类似日历的概念(而不是根据==SimpleTrigger==的精确指定间隔)的job触发计划。
使用CronTrigger,您可以指定诸如“每周五中午”、“每周五和周日上午9:30”、甚至“每周一、三、五周一上午9:00到10:00之间的每5分钟”之类的解雇时间表。

CronTrigger和SimpleTrigger一样可以指定==startTime==和==endTime==来指定任务执行时间区间。

6.1 Cron Expressions
  • [x] Seconds
  • [x] Minutes
  • [x] Hours
  • [x] Day-of-Month
  • [x] Month
  • [x] Day-of-Week
  • [x] Year (optional field)

一个完整的cron表达式是一个字符串,比如==0 0 12 ? * WED==意味着每周三的下午12:00

单个子表达式可以包含范围和/或列表。比如,上面的==WED==中的==DAY OF WEEK==字段可以替换为==MON-FRI==、==MON,WED==,==FRI==,甚至==MON-WED,SAT==。

==DAY OF WEEK==字段中的 ==*== 显然意味着==一周中的每一天==。

所有字段都有一组可以指定的有效值。这些值是非常符合常理的。例如秒和分钟的数值0到59,小时的数值0到23。一个月的天数可以是1-31天,但是你需要注意一个月有多少天!==Months==可以指定值0到11之间,或通过使用字符串==JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC==,==Days-of-Week==之间可以指定值1和7(1 =周日)或通过使用字符串的==SUN, MON, TUE, WED, THU, FRI and SAT==。

字符' / '可用于指定值的增量。例如,如果在==Minutes==字段中输入==0/15==,意思是“每隔15分钟,从0分钟开始”。如果您在分钟字段中使用“3/20”,它将意味着“每20分钟,从第3分钟开始”,换句话说,它与在分钟字段中指定==3,23,43==相同。请注意,==/35==并不意味着==每35分钟==,它的意思是==每个小时中的35分钟,从0分钟开始==,或者换句话说,与指定==0,35==相同。

==?== 字符可以用于月中的日和星期中的日字段

“L”字符可以用于月中的日期和星期中的日期字段。这个字符==last==的简写,但是在这两个字段中含义不同。例如,==DAY OF MONTH== 字段中的值“L”表示“月份的最后一天” ==1月31日==,==非闰年2月28日==。如果单独在==DAT OF WEEK==字段中使用,它的意思就是==7==或==SAT==。但是如果用在==DAY OF WEEK==字段指定值得后面,它表示“一个月的最后一个xxx日”——例如“6L”或“FRIL”都表示“一个月的最后一个星期五”。您还可以指定从该月最后一天开始的偏移量,例如“L-3”,它表示日历月的第三到最后一天。当使用“L”选项时,需要注意不要指定列表或值的范围,会得到混乱或意外的结果。

==W==用于指定最接近给定日期的工作日(星期一至星期五)。例如,如果指定==15W==作为月份字段的值,其含义是:“到本月15日最近的工作日”。

==#==用于指定每月第==n==个工作日。例如,==6#3==或==FRI#3==在==DAY OF WEEK==字段中的值表示“一个月的第三个星期五”。

6.2 Example Cron Expressions
  • [x] ==“0 0/5 * * * ?”== 每五分钟
  • [x] ==“0 0/5 * * * ?”== 每五分钟后的第10秒
  • [x] ==“0 30 10-13 ? * WED,FRI”== 每周三、周五的10:30、11:30、12:30和13:30
  • [x] ==“0 0/30 8-9 5,20 * ?”== 每月的5号至20号的8点到10点间没隔30分钟执行一次,注意==trigger==不会再10:00am执行,仅会在8:00,8:30,9:00,9:30时间段执行;
6.3 Building CronTriggers

==CronTrigger==实例可以通过==TriggerBuilder==构建trigger的主要属性,再通过==CronScheduleBuilder==构建==CronTrigger==的指定属性


import static org.quartz.TriggerBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.DateBuilder.*:
6.3.1 创建一个trigger在每天的上午8点到下午5点每间隔2分钟触发一次
  trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 0/2 8-17 * * ?"))
    .forJob("myJob", "group1")
    .build();
6.3.2 创建一个trigger在每天的上午10:42执行一次

 trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(dailyAtHourAndMinute(10, 42))
    .forJob(myJobKey)
    .build();

或者


  trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 42 10 * * ?"))
    .forJob(myJobKey)
    .build();
6.3.3 创建一个trigger在每周三的上午10:42执行一次,并指定时区
  
  trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(weeklyOnDayAndHourAndMinute(DateBuilder.WEDNESDAY, 10, 42))
    .forJob(myJobKey)
    .inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
    .build();

或者


  trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 42 10 ? * WED"))
    .inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
    .forJob(myJobKey)
    .build();
6.4 CronTrigger Misfire Instructions

下面的执行可以告知==Quartz==当CronTrigger错过执行时该干点啥,以下指令作为静态常量存储在==CronTrigger==中

CronTrigger 中的misfire指令静态常量

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
MISFIRE_INSTRUCTION_DO_NOTHING
MISFIRE_INSTRUCTION_FIRE_NOW

所有的trigger 都拥有指令==Trigger.MISFIRE_INSTRUCTION_SMART_POLICY==,并且这个指令也是所有trigger的默认misfire类型,不过在==CronTrigger==中被替换为==MISFIRE_INSTRUCTION_FIRE_NOW==

创建一个==CronTrigger==并指定 simple schedule 中的misfire 指令

 trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 0/2 8-17 * * ?")
        ..withMisfireHandlingInstructionFireAndProceed())
    .forJob("myJob", "group1")
    .build();

7. TriggerListeners and JobListeners

trigger 事件监听 job 事件监听,==TriggerListeners==trigger的监听事件,==JobListeners==job的监听事件;

7.1 TriggerListener 接口

包括 trigger fire 和 trigger misfire


public interface TriggerListener {

    public String getName();

    public void triggerFired(Trigger trigger, JobExecutionContext context);

    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context);

    public void triggerMisfired(Trigger trigger);

    public void triggerComplete(Trigger trigger, JobExecutionContext context,
            int triggerInstructionCode);
}

7.2 JobListener 接口

job 相关的事件主要包括job即将被执行和job已经执行完毕

public interface JobListener {

    public String getName();

    public void jobToBeExecuted(JobExecutionContext context);

    public void jobExecutionVetoed(JobExecutionContext context);

    public void jobWasExecuted(JobExecutionContext context,
            JobExecutionException jobException);

}

7.3 配置自己的监听器

只要实现==org.quartz.TriggerListener== 或者 ==org.quartz.JobListener interface==,便实现了自己的监听器,然后把监听器注册到==scheduler==就可以使用了,前提你要给你的监听器起个名字

除了简单实现上面这两个接口外,你也可以实现==JobListenerSupport==或==TriggerListenerSupport==来实现对自己感兴趣的trigger 和 job 进行监听

使用==Matcher==就可以指定希望哪些==Jobs/Triggers==接收到事件

7.3.1 执行job添加jobListener
scheduler.getListenerManager().addJobListener(myJobListener, KeyMatcher.jobKeyEquals(new JobKey("myJobName", "myJobGroup")));

需要导入的类

import static org.quartz.JobKey.*;
import static org.quartz.impl.matchers.KeyMatcher.*;
import static org.quartz.impl.matchers.GroupMatcher.*;
import static org.quartz.impl.matchers.AndMatcher.*;
import static org.quartz.impl.matchers.OrMatcher.*;
import static org.quartz.impl.matchers.EverythingMatcher.*;
...etc.
7.3.2 上面的例子也可以这样写
scheduler.getListenerManager().addJobListener(myJobListener, jobKeyEquals(jobKey("myJobName", "myJobGroup")));
7.3.3 给指定组下的所有job添加listener
scheduler.getListenerManager().addJobListener(myJobListener, jobGroupEquals("myJobGroup"));
7.3.4 给指定两组的job添加listener
scheduler.getListenerManager().addJobListener(myJobListener, or(jobGroupEquals("myJobGroup"), jobGroupEquals("yourGroup")));
7.3.5 给所有的job添加listener
scheduler.getListenerManager().addJobListener(myJobListener, allJobs());

8. SchedulerListeners

除了Scheduler本身的一些通知事件外,==SchedulerListeners== 和 ==TriggerListeners==,==JobListeners==的功能很相似

事件主要包括job/trigger的添加,移除,==scheduler==的一些异常通知,==scheduler==的==shutdown==通知等;

8.1 SchedulerListener
public interface SchedulerListener {

    public void jobScheduled(Trigger trigger);

    public void jobUnscheduled(String triggerName, String triggerGroup);

    public void triggerFinalized(Trigger trigger);

    public void triggersPaused(String triggerName, String triggerGroup);

    public void triggersResumed(String triggerName, String triggerGroup);

    public void jobsPaused(String jobName, String jobGroup);

    public void jobsResumed(String jobName, String jobGroup);

    public void schedulerError(String msg, SchedulerException cause);

    public void schedulerStarted();

    public void schedulerInStandbyMode();

    public void schedulerShutdown();

    public void schedulingDataCleared();
}

==SchedulerListeners== 使用 ==scheduler’s ListenerManager==注册监听器

添加

scheduler.getListenerManager().addSchedulerListener(mySchedListener);

移除

scheduler.getListenerManager().removeSchedulerListener(mySchedListener);

9. Job Stores

jobstore 用来存储scheduler下的job、trigger、calender等==work data==,选择合适的store方式非常重要

9.1 内存存储

任务信息存储在内容中,scheduler 被关闭或机器故障后,数据就丢了

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
9.2 JDBCJobStore

支持的数据库有==Oracle, PostgreSQL, MySQL, MS SQLServer, HSQLDB, and DB2==,需要创建quartz单独的数据库表,表结构语句在==“docs/dbTables”==下,默认的事务类型==JobStoreTX==(最常见的),如果你需要quartz和你的应用服务使用同一个事务,需要使用事务类型为==JobStoreCMT==,这样的化,quartz会让应用服务来管理quartz事务;

9.2.1 配置quartz 使用JobStoreTx
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
9.2.2 配置数据库委托

数据库委托信息在包==org.quartz.impl.jdbcjobstore==下

org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
9.2.3 quartz数据库表的前缀
org.quartz.jobStore.tablePrefix = QRTZ_
9.2.4 配置数据源
org.quartz.jobStore.dataSource = myDS

可以指定==org.quartz.jobStore.useProperties==为==true==,这样的就是以==String==类型存储==JobDataMaps==信息,而不是==BLOB==

9.3 TerracottaJobStore

TerracottaJobStore可以是集群,也可以是单点的,不过都可以为作业数据提供存储介质,因为数据存储在Terracotta服务器中,因此在应用程序重新启动期间是持久存储的,。它的性能比JDBCJobStore使用数据库要好得多(大约好一个数量级),但是比RAMJobStore慢得多。

9.3.1 配置使用TerracottaJobStore
org.quartz.jobStore.class = org.terracotta.quartz.TerracottaJobStore
org.quartz.jobStore.tcConfigUrl = localhost:9510

10. Configuration, Resource Usage and SchedulerFactory

在使用quartz之前需要配置如下东西:

  • [x] 线程池 ThreadPool
  • [x] 任务存储方式 JobStore
  • [x] 数据库(如果必要的化)DataSources
  • [x] 调度器 Scheduler

ThreadPool

指定了任务同时执行的并发数量,通常来说5个就够了,官方建议

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容