天天看點

spring的quartz、JDK的timer做定時任務基礎

一、quartz

1.相關API介紹:

(1)Scheduler是與程式互動的主要API,主要是用于執行計劃的,schedule由scheduler工廠建立,工廠包括DirectSchedulerFactory 或者 StdSchedulerFactory,後者用的比較多,比較友善

(2)Job是自定義作業需要實作的接口,job分為stateless無狀态和stateful有狀态,

trigger隻執行無狀态的任務,即一個任務不能被并行執行;一個job可被多個trigger關聯,一個trigger隻能關聯一個job,

job的兩個屬性:volatility 和 durability,其中 volatility 表示任務是否被持久化到資料庫存儲,而 durability 表示在沒有 trigger 關聯的時候任務是否被保留,

兩者都是在值為 true 的時候任務被持久化或保留

(3)JobDetail定義作業執行個體,作業名稱群組别等

(4)Trigger定義觸發器,即執行作業的時間計劃,有四種類型:SimpleTrigger,CronTirgger,DateIntervalTrigger,和 NthIncludedDayTrigger,

SimpleTrigger用于在某個特定時間隻執行一次的;Crontirgger 用的多一些,

simpleTrigger主要是做間隔執行任務的,不太适合定時執行任務,對于某些日期或者周幾執行的這種情況 甚至隻能使用crontrigger

(5)TriggerBuilder 用于建構出觸發器執行個體

(6)JobBuilder 建構Jobe執行個體

2.quartz是spring預設的排程架構

3.quartz資料存儲包括兩種存儲方式:RAMJobStore, JobStoreSupport,前者基于記憶體,後者DB,後者持久用的多

4.同一個分組下的Job或Trigger的名稱必須唯一,即一個Job或Trigger的key由名稱(name)和分組(group)組成。

5.JobDetail對象中有JobDataMap,可以在建構JobDetail時用來傳資料,然後在excute方法上下文中取到

6.JobExecutionContext 這個execute方法的參數是定時任務的上下文,其中有目前scheduler、trigger、job以及jobDetail中所有的資料

7.Trigger:

(1)公共屬性:

key:由name和group組成唯一

startTime 任務首次觸發的參照時間,有些是starttime立即觸發,有些是starttime之後一段時間觸發

endTime trigger失效的時間

priority 優先級, 當quartz線程池資源少,而trigger比較多時,同時觸發的trigger之間優先級高的會先被線程執行,優先級預設都是5,可以為任意整數

觸發時間不同的,觸發時間早的總是優先執行,與priority無關

misfire: 錯過觸發,如果scheduler中沒有足夠的線程來執行trigger,那麼就會錯過觸發時間,此時要執行的政策,就是misfire,

不同類型的trigger有不同的misfire,所有trigger有預設的smart misfire,會根據配置動态選擇一個misfire的政策

(2) 常見trigger介紹

i.simpleTrigger

滿足的排程需求是:任務在某個具體時間執行一次或者以指定的間隔重複執行若幹次,屬性包括開始時間,結束時間,執行間隔和執行次數,

它所有的misfire看具體說明

ii.CronTrigger

比simpleTrigger更常用,是基于月曆的一個trigger

Cron Expressions:

表達式中的值都表示的是某一個時刻點

0 * 17 * * ? 
意義:每天從下午5點到下午5:59中的每分鐘激發一次 trigger。它停在下午5:59 是因為值 17 在小時域上,在下午 6 點時,小時變為 18 了,也就不再理會這個trigger,直到下一天的下午5點。
在你希望 trigger 在該域的所有有效值上被激發時使用* 字元。  

           

秒 分 時 月中日 月 周中日 年(可選字段)

通配符表示每個可能的值 ,;

?隻能用于日期和星期的一個,表示沒有特定值,隻是占位而已,spring規定日期和星期有且隻能有一個,另一個就是?表示占位,

看下面的表達式測試

/用于指定值的增量,如: 分鐘處是 3/10 則表示分針走到3時開始,然後每隔20分鐘執行一次 ,如果是增量,那麼 0/3和/3是一樣的* 執行時包括初始時刻,看測試

月份的0-11表示1-12月份, 星期的1-7表示星期日-星期六,也可用單詞前三位大寫表示:JAN FEB等

8.Calendar:

與java.util中的Calendar不同,用來從trigger的某些計劃中排除掉某些時間段,一個calendar執行個體化後,可用于多個trigger,用法如下

9.參考:w3cschool https://www.w3cschool.cn/quartz_doc/quartz_doc-lwuv2d2a.html

public static void main(String[] args) {
       //排程工廠
            StdSchedulerFactory std = new StdSchedulerFactory();
            //排程器
            Scheduler scheduler =std.getScheduler();
            //排程開始,一般shutdown的話排程就會結束,跟線程池的使用類似
            scheduler.start();
            //添加資料集,在job的excute裡可以擷取
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("mother","11");
            jobDataMap.put("uncle","qq");
            //calendar排除一整天,calender必須執行個體化,然後注冊到scheduler中
            HolidayCalendar calendar = new HolidayCalendar();
            //排除掉今天
            calendar.addExcludedDate(new Date());
            scheduler.addCalendar("myCalender",calendar,false,false);
            //name和group組成了這個job唯一的JobKey
            JobDetail jobMike = JobBuilder.newJob(Myjob.class).withIdentity("jobMike","group1")
                    //這裡的durable預設是false的,作業是否在沒有trigger與之關聯時仍然儲存
                    .usingJobData("processor","Mike").storeDurably(true).setJobData(jobDataMap).build();
            //這裡的key由name和group組成,構成了triggerKey 同一個分組下要唯一
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger").
                    //每天10.25執行一次,但是不包括calendar中的那天
                    startNow().withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(10, 26))
                    .modifiedByCalendar("myCalender").withPriority(10).build();
            //trigger公共屬性
            System.out.println(trigger.getKey());
            System.out.println("starttime:"+trigger.getStartTime());
            System.out.println("endtime:"+trigger.getEndTime());
            System.out.println("priority:"+trigger.getPriority());
            //同一個job可以隻添加到計劃中,然後跟不同的多個trigger綁定,實作複雜排程計劃
            scheduler.addJob(jobMike,false);
            scheduler.scheduleJob(cronTriggerTest(jobMike));
            scheduler.scheduleJob(cronTriggerTest1(jobMike));
 
  }
//simpleTrigger舉例
    public static Trigger simpleTriggerTest(){
        //使用DateBuilder構造date,指定任意時間
        Date date = DateBuilder.dateOf(20, 44, 30);
        //目前時間30s後執行
        Date futureDate = DateBuilder.futureDate(30, DateBuilder.IntervalUnit.SECOND);
        SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("mySimple","group1")
                //這裡的simpleSchedule與simpleTrigger對應,最終構造出來就是simpleTrigger,
                // withIntervalInSeconds或者withIntervalInHours()等是間隔時間,
                // withRepeatCount(5)是重複次數,重複5次 則最終會執行6次 ,不限次數則repeatForever()
                .startAt(futureDate).withSchedule(simpleSchedule().withIntervalInSeconds(2).withRepeatCount(5))
                .withPriority(10).build();
        //endAt 何時結束,這個表明立即觸發,date點時結束
        SimpleTrigger trigger1 = TriggerBuilder.newTrigger().withIdentity("mySimple","group1")
                .endAt(date).withSchedule(simpleSchedule().repeatForever())
                .withPriority(10).build();
        //觸發器:在下一個小時的整點觸發,每兩分鐘執行一次
        //這個evenHourDate/evenMinuteDate是給定一個date然後拿這個date的下一個整點時間,null的話會new Date()
        Date date1 = DateBuilder.evenMinuteDate(null);
        SimpleTrigger trigger2 = TriggerBuilder.newTrigger().startAt(date1).
                withSchedule(simpleSchedule().repeatForever().withIntervalInSeconds(2)).build();
        return trigger2;
    }
    
       //cronTrigger舉例
    public static Trigger cronTriggerTest(JobDetail jobDetail){
        //cron expression
        String cron0 = "0/2 * * * * ?";//每兩秒執行一次
        String cron1 = "10 0/2 * * * ?";//每兩分鐘到了之後10s執行
        String cron2 = "0 30 10-13 ? * 4,6";//每周三和周五的10:30 11:30 12:30 13:30執行,有星期的話月份日就要?占位
        String cron3 = "0 0/30 8,9 5,20 * ?"; //每個月5号和20号上午8 8:30 9 9:30執行
        String cron4 = "0 0/5 9-10 * * ?"; //
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().
                withSchedule(CronScheduleBuilder.cronSchedule(cron0)).forJob(jobDetail).build();
        return cronTrigger;
    }

//自定義一個任務,需要實作Job接口
public class Myjob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        System.out.println("processor is "+jobDataMap.getString("processor"));
       for (Map.Entry<String, Object> stringObjectEntry : jobDataMap.entrySet()) {
            System.out.println(stringObjectEntry.getKey()+stringObjectEntry.getValue());
        }
        System.out.println(jobDetail.getKey().getName());
        System.out.println(jobDetail.getKey().getGroup());
        System.out.println("這是一個測試用的quartz的job");
    }
}
           

10.quartz叢集搭建:

參考:https://www.jb51.net/article/139597.htm

(1)資料庫刷11張表

(2)叢集是通過DB感應彼此的,彼此之間沒有心跳感應

(3)代碼實作: 叢集之間的配置檔案和心跳代碼必須完全一樣

自定義job實作:

package com.sf.express.config.quartz.job;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
import java.util.Date;

@Slf4j
@Component
public class HeartBeatJob extends QuartzJobBean  {
    //bean隻能從spring上下文中擷取
   static RedisUtil redisUtil;
   屬性的處理
   @Autowired
    public  void setRedis(RedisUtil redisUtil1){
        redisUtil1 = redisUtil1;
    }
    //定時任務,每2分鐘走一次
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) {
    方法裡用到的spring的bean,隻能從容器上下文中去重新拿,這裡的調用時quartz重新反射了一個執行個體,不是spring中的bean
        log.info("---定時任務開始---{}",new Date());
        if (redisUtil==null){
            redisUtil = (RedisUtil)SpringUtil.getBean(RedisUtil.class);
        }
        if(qrVisWgtDataMapper==null){
            qrVisWgtDataMapper = (QrVisWgtDataMapper)SpringUtil.getBean(QrVisWgtDataMapper.class);
        }
            Object heartObj = redisUtil.get("heartbeat");
      ...
    }
    }
           

springboot中自動配置quartz的實作:

叢集環境下的quartz一定不能随便更改類似cronExp或者trigger名稱這些,每個屬性都會入庫,改了就出問題

quartz原理圖,其實就是将多個任務扔到排程容器中,将多個trigger扔到容器中,然後再将trigger和job綁定起來,綁定的過程在trigger的建立過程中,

是以一般來說一個應用一個排程器就夠了

spring的quartz、JDK的timer做定時任務基礎
/**
 * @Description: 注冊定時任務
 */
@Configuration
public class QuartzConfiguration {
    //cron表達式會入庫,同一個trigger表達式會在第一次寫入後不再寫入,如果要變執行計劃,可以增加一個trigger
    private String cronExpression = "0 */2 * * * ?";
    @Autowired
    DataSource dataSource;

    private static final String QUARTZ_CONFIG = "/quartz.properties";
    private static final String  JOB_NAME= "heartBeanJob";
    private static final String  TRIGGER_NAME= "heartBeanTrigger";

    /**
     * @Author: 01398017
     * @Description: 讀取屬性檔案
     * @DateTime: 2020/8/6
     * @Params:
     * @Return
     */
    public Properties getProperties() {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource(QUARTZ_CONFIG));
        try {
            propertiesFactoryBean.afterPropertiesSet();
            return propertiesFactoryBean.getObject();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
   @Bean
    public SchedulerFactoryBean getScheduler(@Qualifier(TRIGGER_NAME) Trigger heartBeatTrigger,
                                             @Qualifier(DELETE_HISTORY_DATA_TRIGGER_NAME) Trigger deletingTrigger,
                                             @Qualifier(JOB_NAME) JobDetail heartBeat,
                                             @Qualifier(DELETE_JOB) JobDetail deletingJob )  {
        SchedulerFactoryBean stdSchedulerFactory = new SchedulerFactoryBean();
        //這裡設定是否自動開啟scheduler,預設true
        stdSchedulerFactory.setAutoStartup(false);
        //設定配置檔案
        stdSchedulerFactory.setQuartzProperties(getProperties());
        stdSchedulerFactory.setDataSource(dataSource);
        //添加任務,這裡可以添加多個jobdetails,demo裡隻建立了一個trigger和job,另一個建立的類似
        stdSchedulerFactory.setJobDetails(heartBeat,deletingJob);
        //添加多個觸發器
        stdSchedulerFactory.setTriggers(heartBeatTrigger,deletingTrigger);

        try {
            stdSchedulerFactory.afterPropertiesSet();
        } catch (Exception e) {
            e.printStackTrace();
        }
        stdSchedulerFactory.start();
        return stdSchedulerFactory;
    }

    @Bean
    public Trigger getCronTrigger(@Qualifier(JOB_NAME) JobDetail jobDetail) {
        //triggerName代表一個trigger執行個體,會寫入資料庫,不能随便更改,改一次就會多一個trigger
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(TRIGGER_NAME).
這裡的觸發器和job進行一一綁定                withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)).forJob(jobDetail).build();
        return cronTrigger;
    }

      @Bean(JOB_NAME)
    public  JobDetail getJob(){

        return JobBuilder.newJob(HeartBeatJob.class). //jobname代表一個job會入庫,不能随便更改
                withIdentity(JOB_NAME).storeDurably(true).build();
    }


##*******Quartz提供兩種基本作業存儲類型
#******* 1、JDBC作業存儲持久化
#### Quartz配置:
## *****排程器的配置:
#排程器名稱
org.quartz.scheduler.instanceName= scadaClusteredScheduler
#ID設定為自動擷取 每一個必須不同 (所有排程器執行個體中是唯一的)如果使用叢集,instanceId必須唯一,設定成AUTO
org.quartz.scheduler.instanceId= AUTO
## *******jobStore 工作存儲配置:
#啟動jdbcJobStore而非RamJobStore:
spring.quartz.job-store-type=jdbc
#資料儲存方式為持久化spring.quartz.job-store-type
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
#StdJDBCDelegate說明支援叢集
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#quartz内部表的字首
org.quartz.jobStore.tablePrefix=QRTZ_
#是否加入叢集
org.quartz.jobStore.isClustered=true
# 分布式節點有效性檢查時間間隔,機關:毫秒
org.quartz.jobStore.clusterCheckinInterval=10000
#容許的最大作業延長時間,最大能忍受的觸發逾時時間,如果超過則認為“失誤”,不敢再記憶體中還是資料中都要配置
org.quartz.jobStore.misfireThreshold = 6000
## *******線程池配置:
#ThreadPool實作的類名
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
#線程數量
org.quartz.threadPool.threadCount=5
#線程優先級
org.quartz.threadPool.threadPriority=5
#配置為守護線程,設定後任務将不會執行
#org.quartz.threadPool.makeThreadsDaemons=true
#配置是否啟動自動加載資料庫内的定時任務,預設true
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
           

quartz叢集建表腳本

參考:https://blog.csdn.net/xiaohuaidan007/article/details/77485673?utm_source=blogxgwz4
--以下是quartz叢集表
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; --cron觸發器資訊
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS; --以blob形式存儲觸發器
DROP TABLE IF EXISTS QRTZ_TRIGGERS; --所有觸發器的總表
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS; --job
DROP TABLE IF EXISTS QRTZ_CALENDARS; --calendar
--cron需要的幾張表:qrtz_triggers,qrtz_cron_triggers,qrtz_fired_triggers ,qrtz_job_details
CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) 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))
ENGINE=InnoDB;

CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) 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(200) 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))
ENGINE=InnoDB;

CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) 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))
ENGINE=InnoDB;

CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(120) 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))
ENGINE=InnoDB;

CREATE TABLE QRTZ_SIMPROP_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) 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))
ENGINE=InnoDB;

CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB;

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
INSTANCE_NAME VARCHAR(200) 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(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB;

CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB;

CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB;

CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);

CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);

CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);


           

二、Timer

1.代碼示範:

public static void main(String[] args) {
        Timer   timer = new Timer();
        TimerTask myTask = new TimerTask(){
            @Override
            public void run() {
                System.out.println("Timer測試");
            }
        } ;
        //目前時間延遲多久開始,間隔多久執行一次
      //  timer.schedule(myTask,1000L,1000L);
        Calendar calendar = Calendar.getInstance();
        calendar.set(2020,6,26,17,51,0);
        //從什麼時間開始,間隔多久執行一次
        //timer.schedule(myTask,calendar.getTime(),2000L);
        //何時開始執行一次
        //timer.schedule(myTask,calendar.getTime());
        //從現在開始延遲多久執行一次
        timer.schedule(myTask,3000L);
    }
           

2.參考 https://blog.csdn.net/u014761700/article/details/79555768

3.原理和缺陷

(1)Timer其實就是最簡單的單線程任務,将線程中的任務執行内容的run方法進行調用

(2)timer缺陷很明顯,單線程,如果任務執行時間超過了間隔時間,就會導緻後面的任務因為阻塞等待而無法按時執行,此外單線程一旦報錯,線程就會被打斷,那麼後面的任務也就無法執行,是以timer隻适合執行比較簡單快速的任務

(3**)一般建議使用ScheduledThreadPoolExecutor替換timer建立簡單邏輯的定時任務**,因為線程池可做保證,使得任務并發執行