spring boot + quartz 集群

spring boot bean配置:

@Configuration
public class QuartzConfig {
       
        @Value("${quartz.scheduler.instanceName}")
        private String quartzInstanceName;
       
        @Value("${org.quartz.dataSource.myDS.driver}")
        private String myDSDriver;
       
        @Value("${org.quartz.dataSource.myDS.URL}")
        private String myDSURL;
       
        @Value("${org.quartz.dataSource.myDS.user}")
        private String myDSUser;
       
        @Value("${org.quartz.dataSource.myDS.password}")
        private String myDSPassword;
       
        @Value("${org.quartz.dataSource.myDS.maxConnections}")
        private String myDSMaxConnections;
       
       
    /**
     * 设置属性
     * @return
     * @throws IOException
     */
    private Properties quartzProperties() throws IOException {
        Properties prop = new Properties();
        prop.put("quartz.scheduler.instanceName", quartzInstanceName);
        prop.put("org.quartz.scheduler.instanceId", "AUTO");
        prop.put("org.quartz.scheduler.skipUpdateCheck", "true");
        prop.put("org.quartz.scheduler.jmx.export", "true");
       
        prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
        prop.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
        prop.put("org.quartz.jobStore.dataSource", "quartzDataSource");
        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
        prop.put("org.quartz.jobStore.isClustered", "true");
       
        prop.put("org.quartz.jobStore.clusterCheckinInterval", "20000");
        prop.put("org.quartz.jobStore.dataSource", "myDS");
        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
        prop.put("org.quartz.jobStore.misfireThreshold", "120000");
        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
        prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE");
       
        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        prop.put("org.quartz.threadPool.threadCount", "10");
        prop.put("org.quartz.threadPool.threadPriority", "5");
        prop.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", "true");
       
        prop.put("org.quartz.dataSource.myDS.driver", myDSDriver);
        prop.put("org.quartz.dataSource.myDS.URL", myDSURL);
        prop.put("org.quartz.dataSource.myDS.user", myDSUser);
        prop.put("org.quartz.dataSource.myDS.password", myDSPassword);
        System.out.println("myDSMaxConnections:" + myDSMaxConnections);
        prop.put("org.quartz.dataSource.myDS.maxConnections", myDSMaxConnections);
       
        prop.put("org.quartz.plugin.triggHistory.class", "org.quartz.plugins.history.LoggingJobHistoryPlugin");
        prop.put("org.quartz.plugin.shutdownhook.class", "org.quartz.plugins.management.ShutdownHookPlugin");
        prop.put("org.quartz.plugin.shutdownhook.cleanShutdown", "true");
        return prop;
    }
   
    @Bean  
    public SchedulerFactoryBean schedulerFactoryBean(@Qualifier("dialogJobTrigger") Trigger cronJobTrigger) throws IOException {  
        SchedulerFactoryBean factory = new SchedulerFactoryBean();  
        // this allows to update triggers in DB when updating settings in config file:  
        //用于quartz集群,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了  
        factory.setOverwriteExistingJobs(true);  
        //用于quartz集群,加载quartz数据源  
        //factory.setDataSource(dataSource);    
        //QuartzScheduler 延时启动,应用启动完10秒后 QuartzScheduler 再启动  
        factory.setStartupDelay(10);
        //用于quartz集群,加载quartz数据源配置  
        factory.setQuartzProperties(quartzProperties());
        factory.setAutoStartup(true);
        factory.setApplicationContextSchedulerContextKey("applicationContext");
        //注册触发器  
        factory.setTriggers(cronJobTrigger);
     //直接使用配置文件
//        factory.setConfigLocation(new FileSystemResource(this.getClass().getResource("/quartz.properties").getPath()));
        return factory;  
    }
   
   
    /**
     * 加载job
     * @return
     */
    @Bean  
    public JobDetailFactoryBean updateDialogStatusJobDetail() {  
        return createJobDetail(InvokingJobDetailDetailFactory.class, "updateDialogStatusGroup", "dialogJob");  
    }  

    /**
     * 加载触发器
     * @param jobDetail
     * @return
     */
    @Bean(name = "dialogJobTrigger")  
    public CronTriggerFactoryBean dialogStatusJobTrigger(@Qualifier("updateDialogStatusJobDetail") JobDetail jobDetail) {  
        return dialogStatusTrigger(jobDetail, "0 0 0/1 * * ?");  
    }     

/**     * 创建job工厂     * @param jobClass     * @param groupName     * @param targetObject     * @return     */





   
privatestaticJobDetailFactoryBean createJobDetail(Class<?> jobClass,String groupName,String targetObject){         
JobDetailFactoryBean factoryBean =newJobDetailFactoryBean();          factoryBean
.setJobClass(jobClass);          factoryBean
.setDurability(true);          factoryBean
.setRequestsRecovery(true);        factoryBean
.setGroup(groupName);       
Map<String,String> map =newHashMap<>();        map
.put("targetObject", targetObject);        map
.put("targetMethod","execute");        factoryBean
.setJobDataAsMap(map);       
return factoryBean;     
}     

/**     * 创建触发器工厂     * @param jobDetail     * @param cronExpression     * @return     */




   
privatestaticCronTriggerFactoryBean dialogStatusTrigger(JobDetail jobDetail,String cronExpression){         
CronTriggerFactoryBean factoryBean =newCronTriggerFactoryBean();          factoryBean
.setJobDetail(jobDetail);        factoryBean
.setCronExpression (cronExpression);       
return factoryBean;     
}   

}

  

InvokingJobDetailDetailFactory对象:
public class InvokingJobDetailDetailFactory extends QuartzJobBean{

        // 计划任务所在类  
    private String targetObject;
 
    // 具体需要执行的计划任务  
    private String targetMethod;
   
    private ApplicationContext ctx;
   
        @Override
        protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
                try {
            Object otargetObject = ctx.getBean(targetObject);
            Method m = null;  
            try {  
                m = otargetObject.getClass().getMethod(targetMethod);  
                m.invoke(otargetObject);  
            } catch (SecurityException e) {  
                e.printStackTrace();  
            } catch (NoSuchMethodException e) {  
                e.printStackTrace();  
            }  
        } catch (Exception e) {  
            throw new JobExecutionException(e);  
        }
        }

    public void setApplicationContext(ApplicationContext applicationContext) {  
        this.ctx = applicationContext;  
    }  
 
    public void setTargetObject(String targetObject) {  
        this.targetObject = targetObject;  
    }  
 
    public void setTargetMethod(String targetMethod) {  
        this.targetMethod = targetMethod;  
    }
}

 备注:set方法不能少,setApplicationContext中的applicationContext与factory.setApplicationContextSchedulerContextKey(“applicationContext”)填入的值有关,其原理由InvokingJobDetailDetailFactory父类中的BeanWrapper实现。

sql脚本:–

-- 表的结构 `qrtz_blob_triggers`
--

CREATE TABLE IF NOT EXISTS `qrtz_blob_triggers` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `TRIGGER_NAME` varchar(120) NOT NULL,
  `TRIGGER_GROUP` varchar(120) NOT NULL,
  `BLOB_DATA` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

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

--
-- 表的结构 `qrtz_calendars`
--

CREATE TABLE IF NOT EXISTS `qrtz_calendars` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `CALENDAR_NAME` varchar(120) NOT NULL,
  `CALENDAR` blob NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

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

--
-- 表的结构 `qrtz_cron_triggers`
--

CREATE TABLE IF NOT EXISTS `qrtz_cron_triggers` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `TRIGGER_NAME` varchar(120) NOT NULL,
  `TRIGGER_GROUP` varchar(120) NOT NULL,
  `CRON_EXPRESSION` varchar(120) NOT NULL,
  `TIME_ZONE_ID` varchar(80) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

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

--
-- 表的结构 `qrtz_fired_triggers`
--

CREATE TABLE IF NOT EXISTS `qrtz_fired_triggers` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `ENTRY_ID` varchar(95) NOT NULL,
  `TRIGGER_NAME` varchar(120) NOT NULL,
  `TRIGGER_GROUP` varchar(120) NOT NULL,
  `INSTANCE_NAME` varchar(120) NOT NULL,
  `FIRED_TIME` bigint(13) NOT NULL,
  `SCHED_TIME` bigint(13) NOT NULL,
  `PRIORITY` int(11) NOT NULL,
  `STATE` varchar(16) NOT NULL,
  `JOB_NAME` varchar(120) DEFAULT NULL,
  `JOB_GROUP` varchar(120) DEFAULT NULL,
  `IS_NONCONCURRENT` varchar(1) DEFAULT NULL,
  `REQUESTS_RECOVERY` varchar(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

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

--
-- 表的结构 `qrtz_job_details`
--

CREATE TABLE IF NOT EXISTS `qrtz_job_details` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `JOB_NAME` varchar(120) NOT NULL,
  `JOB_GROUP` varchar(120) NOT NULL,
  `DESCRIPTION` varchar(250) DEFAULT 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
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

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

--
-- 表的结构 `qrtz_locks`
--

CREATE TABLE IF NOT EXISTS `qrtz_locks` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `LOCK_NAME` varchar(40) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

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

--
-- 表的结构 `qrtz_paused_trigger_grps`
--

CREATE TABLE IF NOT EXISTS `qrtz_paused_trigger_grps` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `TRIGGER_GROUP` varchar(120) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

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

--
-- 表的结构 `qrtz_scheduler_state`
--

CREATE TABLE IF NOT EXISTS `qrtz_scheduler_state` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `INSTANCE_NAME` varchar(120) NOT NULL,
  `LAST_CHECKIN_TIME` bigint(13) NOT NULL, 
`CHECKIN_INTERVAL` bigint(13) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

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

--
--表的结构`qrtz_simple_triggers`
--CREATE TABLE IF NOT EXISTS

`qrtz_simple_triggers`( 
`SCHED_NAME` varchar(120) NOT NULL, 
`TRIGGER_NAME` varchar(120) NOT NULL, 
`TRIGGER_GROUP` varchar(120) NOT NULL, 
`REPEAT_COUNT` bigint(7) NOT NULL, 
`REPEAT_INTERVAL` bigint(12) NOT NULL, 
`TIMES_TRIGGERED` bigint(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

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

--
--表的结构`qrtz_simprop_triggers`
--CREATE TABLE IF NOT EXISTS

`qrtz_simprop_triggers`( 
`SCHED_NAME` varchar(120) NOT NULL, 
`TRIGGER_NAME` varchar(120) NOT NULL, 
`TRIGGER_GROUP` varchar(120) NOT NULL, 
`STR_PROP_1` varchar(512) DEFAULT NULL, 
`STR_PROP_2` varchar(512) DEFAULT NULL, 
`STR_PROP_3` varchar(512) DEFAULT NULL, 
`INT_PROP_1`int(11) DEFAULT NULL, 
`INT_PROP_2`int(11) DEFAULT NULL, 
`LONG_PROP_1` bigint(20) DEFAULT NULL, 
`LONG_PROP_2` bigint(20) DEFAULT NULL, 
`DEC_PROP_1`decimal(13,4) DEFAULT NULL, 
`DEC_PROP_2`decimal(13,4) DEFAULT NULL, 
`BOOL_PROP_1` varchar(1) DEFAULT NULL, 
`BOOL_PROP_2` varchar(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

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

--
--表的结构`qrtz_triggers`
--CREATE TABLE IF NOT EXISTS

`qrtz_triggers`( 
`SCHED_NAME` varchar(120) NOT NULL, 
`TRIGGER_NAME` varchar(120) NOT NULL, 
`TRIGGER_GROUP` varchar(120) NOT NULL, 
`JOB_NAME` varchar(120) NOT NULL, 
`JOB_GROUP` varchar(120) NOT NULL, 
`DESCRIPTION` varchar(250) DEFAULT NULL, 
`NEXT_FIRE_TIME` bigint(13) DEFAULT NULL, 
`PREV_FIRE_TIME` bigint(13) DEFAULT NULL, 
`PRIORITY`int(11) DEFAULT NULL, 
`TRIGGER_STATE` varchar(16) NOT NULL, 
`TRIGGER_TYPE` varchar(8) NOT NULL, 
`START_TIME` bigint(13) NOT NULL, 
`END_TIME` bigint(13) DEFAULT NULL, 
`CALENDAR_NAME` varchar(200) DEFAULT NULL, 
`MISFIRE_INSTR` smallint(2) DEFAULT NULL, 
`JOB_DATA` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

--
--Indexesfor dumped tables
--

--
--Indexesfor table `qrtz_blob_triggers`
--ALTER TABLE
`qrtz_blob_triggers`  ADD PRIMARY KEY
(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),  ADD KEY
`SCHED_NAME`(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`);

--
--Indexesfor table `qrtz_calendars`
--ALTER TABLE
`qrtz_calendars`  ADD PRIMARY KEY
(`SCHED_NAME`,`CALENDAR_NAME`);

--
--Indexesfor table `qrtz_cron_triggers`
--ALTER TABLE
`qrtz_cron_triggers`  ADD PRIMARY KEY
(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`);

--
--Indexesfor table `qrtz_fired_triggers`
--ALTER TABLE
`qrtz_fired_triggers`  ADD PRIMARY KEY
(`SCHED_NAME`,`ENTRY_ID`),  ADD KEY
`IDX_QRTZ_FT_TRIG_INST_NAME`(`SCHED_NAME`,`INSTANCE_NAME`),  ADD KEY
`IDX_QRTZ_FT_INST_JOB_REQ_RCVRY`(`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`),  ADD KEY
`IDX_QRTZ_FT_J_G`(`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),  ADD KEY
`IDX_QRTZ_FT_JG`(`SCHED_NAME`,`JOB_GROUP`),  ADD KEY
`IDX_QRTZ_FT_T_G`(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),  ADD KEY
`IDX_QRTZ_FT_TG`(`SCHED_NAME`,`TRIGGER_GROUP`);

--
--Indexesfor table `qrtz_job_details`
--ALTER TABLE
`qrtz_job_details`  ADD PRIMARY KEY
(`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),  ADD KEY
`IDX_QRTZ_J_REQ_RECOVERY`(`SCHED_NAME`,`REQUESTS_RECOVERY`),  ADD KEY
`IDX_QRTZ_J_GRP`(`SCHED_NAME`,`JOB_GROUP`);

--
--Indexesfor table `qrtz_locks`
--ALTER TABLE
`qrtz_locks`  ADD PRIMARY KEY
(`SCHED_NAME`,`LOCK_NAME`);

--
--Indexesfor table `qrtz_paused_trigger_grps`
--ALTER TABLE
`qrtz_paused_trigger_grps`  ADD PRIMARY KEY
(`SCHED_NAME`,`TRIGGER_GROUP`);

--
--Indexesfor table `qrtz_scheduler_state`
--ALTER TABLE
`qrtz_scheduler_state`  ADD PRIMARY KEY
(`SCHED_NAME`,`INSTANCE_NAME`);

--
--Indexesfor table `qrtz_simple_triggers`
--ALTER TABLE
`qrtz_simple_triggers`  ADD PRIMARY KEY
(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`);

--
--Indexesfor table `qrtz_simprop_triggers`
--ALTER TABLE
`qrtz_simprop_triggers`  ADD PRIMARY KEY
(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`);

--
--Indexesfor table `qrtz_triggers`
--ALTER TABLE
`qrtz_triggers`  ADD PRIMARY KEY
(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),  ADD KEY
`IDX_QRTZ_T_J`(`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),  ADD KEY
`IDX_QRTZ_T_JG`(`SCHED_NAME`,`JOB_GROUP`),  ADD KEY
`IDX_QRTZ_T_C`(`SCHED_NAME`,`CALENDAR_NAME`(191)),  ADD KEY
`IDX_QRTZ_T_G`(`SCHED_NAME`,`TRIGGER_GROUP`),  ADD KEY
`IDX_QRTZ_T_STATE`(`SCHED_NAME`,`TRIGGER_STATE`),  ADD KEY
`IDX_QRTZ_T_N_STATE`(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),  ADD KEY
`IDX_QRTZ_T_N_G_STATE`(`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),  ADD KEY
`IDX_QRTZ_T_NEXT_FIRE_TIME`(`SCHED_NAME`,`NEXT_FIRE_TIME`),  ADD KEY
`IDX_QRTZ_T_NFT_ST`(`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),  ADD KEY
`IDX_QRTZ_T_NFT_MISFIRE`(`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),  ADD KEY
`IDX_QRTZ_T_NFT_ST_MISFIRE`(`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),  ADD KEY
`IDX_QRTZ_T_NFT_ST_MISFIRE_GRP`(`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`);

--
--限制导出的表
--

--
--限制表`qrtz_blob_triggers`
--ALTER TABLE
`qrtz_blob_triggers`  ADD CONSTRAINT
`qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) REFERENCES `qrtz_triggers`(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`);

--
--限制表`qrtz_cron_triggers`
--ALTER TABLE
`qrtz_cron_triggers`  ADD CONSTRAINT
`qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) REFERENCES `qrtz_triggers`(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`);

--
--限制表`qrtz_simple_triggers`
--ALTER TABLE
`qrtz_simple_triggers`  ADD CONSTRAINT
`qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) REFERENCES `qrtz_triggers`(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`);

--
--限制表`qrtz_simprop_triggers`
--ALTER TABLE
`qrtz_simprop_triggers`  ADD CONSTRAINT
`qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) REFERENCES `qrtz_triggers`(`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`);

--
--限制表`qrtz_triggers`
--ALTER TABLE
`qrtz_triggers`  ADD CONSTRAINT
`qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`) REFERENCES `qrtz_job_details`(`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`);


quartz集群实现原理,利用数据库记录job行为,并通过锁机制,使job在同一次中仅运行一次。

http://codecloud.net/135188.html

 quartz2.2.1创建表结构

--
-- A hint submitted by a user: Oracle DB MUST be created as "shared" and the 
-- job_queue_processes parameter  must be greater than 2
-- However, these settings are pretty much standard after any
-- Oracle install, so most users need not worry about this.
--
-- Many other users (including the primary author of Quartz) have had success
-- runing in dedicated mode, so only consider the above as a hint ;-)
--

delete from qrtz_fired_triggers;
delete from qrtz_simple_triggers;
delete from qrtz_simprop_triggers;
delete from qrtz_cron_triggers;
delete from qrtz_blob_triggers;
delete from qrtz_triggers;
delete from qrtz_job_details;
delete from qrtz_calendars;
delete from qrtz_paused_trigger_grps;
delete from qrtz_locks;
delete from qrtz_scheduler_state;

drop table qrtz_calendars;
drop table qrtz_fired_triggers;
drop table qrtz_blob_triggers;
drop table qrtz_cron_triggers;
drop table qrtz_simple_triggers;
drop table qrtz_simprop_triggers;
drop table qrtz_triggers;
drop table qrtz_job_details;
drop table qrtz_paused_trigger_grps;
drop table qrtz_locks;
drop table qrtz_scheduler_state;

-- 存储每一个已配置的 Job 的详细信息
CREATE TABLE qrtz_job_details
  (
    SCHED_NAME VARCHAR2(120) NOT NULL,
    JOB_NAME  VARCHAR2(200) NOT NULL,
    JOB_GROUP VARCHAR2(200) NOT NULL,
    DESCRIPTION VARCHAR2(250) NULL,
    JOB_CLASS_NAME   VARCHAR2(250) NOT NULL, 
    IS_DURABLE VARCHAR2(1) NOT NULL,
    IS_NONCONCURRENT VARCHAR2(1) NOT NULL,
    IS_UPDATE_DATA VARCHAR2(1) NOT NULL,
    REQUESTS_RECOVERY VARCHAR2(1) NOT NULL,
    JOB_DATA BLOB NULL,
    CONSTRAINT QRTZ_JOB_DETAILS_PK PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
--  存储已配置的 Trigger 的信息
CREATE TABLE qrtz_triggers
  (
    SCHED_NAME VARCHAR2(120) NOT NULL,
    TRIGGER_NAME VARCHAR2(200) NOT NULL,
    TRIGGER_GROUP VARCHAR2(200) NOT NULL,
    JOB_NAME  VARCHAR2(200) NOT NULL, 
    JOB_GROUP VARCHAR2(200) NOT NULL,
    DESCRIPTION VARCHAR2(250) NULL,
    NEXT_FIRE_TIME NUMBER(13) NULL,
    PREV_FIRE_TIME NUMBER(13) NULL,
    PRIORITY NUMBER(13) NULL,
    TRIGGER_STATE VARCHAR2(16) NOT NULL,
    TRIGGER_TYPE VARCHAR2(8) NOT NULL,
    START_TIME NUMBER(13) NOT NULL,
    END_TIME NUMBER(13) NULL,
    CALENDAR_NAME VARCHAR2(200) NULL,
    MISFIRE_INSTR NUMBER(2) NULL,
    JOB_DATA BLOB NULL,
    CONSTRAINT QRTZ_TRIGGERS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    CONSTRAINT QRTZ_TRIGGER_TO_JOBS_FK FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) 
      REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) 
);
-- 存储简单的 Trigger,包括重复次数,间隔,以及已触的次数
CREATE TABLE qrtz_simple_triggers
  (
    SCHED_NAME VARCHAR2(120) NOT NULL,
    TRIGGER_NAME VARCHAR2(200) NOT NULL,
    TRIGGER_GROUP VARCHAR2(200) NOT NULL,
    REPEAT_COUNT NUMBER(7) NOT NULL,
    REPEAT_INTERVAL NUMBER(12) NOT NULL,
    TIMES_TRIGGERED NUMBER(10) NOT NULL,
    CONSTRAINT QRTZ_SIMPLE_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    CONSTRAINT QRTZ_SIMPLE_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
  REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
-- 存储 Cron Trigger,包括 Cron 表达式和时区信息
CREATE TABLE qrtz_cron_triggers
  (
    SCHED_NAME VARCHAR2(120) NOT NULL,
    TRIGGER_NAME VARCHAR2(200) NOT NULL,
    TRIGGER_GROUP VARCHAR2(200) NOT NULL,
    CRON_EXPRESSION VARCHAR2(120) NOT NULL,
    TIME_ZONE_ID VARCHAR2(80),
    CONSTRAINT QRTZ_CRON_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    CONSTRAINT QRTZ_CRON_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
      REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE qrtz_simprop_triggers
  (          
    SCHED_NAME VARCHAR2(120) NOT NULL,
    TRIGGER_NAME VARCHAR2(200) NOT NULL,
    TRIGGER_GROUP VARCHAR2(200) NOT NULL,
    STR_PROP_1 VARCHAR2(512) NULL,
    STR_PROP_2 VARCHAR2(512) NULL,
    STR_PROP_3 VARCHAR2(512) NULL,
    INT_PROP_1 NUMBER(10) NULL,
    INT_PROP_2 NUMBER(10) NULL,
    LONG_PROP_1 NUMBER(13) NULL,
    LONG_PROP_2 NUMBER(13) NULL,
    DEC_PROP_1 NUMERIC(13,4) NULL,
    DEC_PROP_2 NUMERIC(13,4) NULL,
    BOOL_PROP_1 VARCHAR2(1) NULL,
    BOOL_PROP_2 VARCHAR2(1) NULL,
    CONSTRAINT QRTZ_SIMPROP_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    CONSTRAINT QRTZ_SIMPROP_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
      REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
-- Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,<span style="color:#800080;">JobStore</span> 并不知道如何存储实例的时候)
CREATE TABLE qrtz_blob_triggers
  (
    SCHED_NAME VARCHAR2(120) NOT NULL,
    TRIGGER_NAME VARCHAR2(200) NOT NULL,
    TRIGGER_GROUP VARCHAR2(200) NOT NULL,
    BLOB_DATA BLOB NULL,
    CONSTRAINT QRTZ_BLOB_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    CONSTRAINT QRTZ_BLOB_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
-- 以 Blob 类型存储 Quartz 的 Calendar 信息
CREATE TABLE qrtz_calendars
  (
    SCHED_NAME VARCHAR2(120) NOT NULL,
    CALENDAR_NAME  VARCHAR2(200) NOT NULL, 
    CALENDAR BLOB NOT NULL,
    CONSTRAINT QRTZ_CALENDARS_PK PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);
-- 存储已暂停的 Trigger 组的信息 
CREATE TABLE qrtz_paused_trigger_grps
  (
    SCHED_NAME VARCHAR2(120) NOT NULL,
    TRIGGER_GROUP  VARCHAR2(200) NOT NULL, 
    CONSTRAINT QRTZ_PAUSED_TRIG_GRPS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
-- 存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息
CREATE TABLE qrtz_fired_triggers 
  (
    SCHED_NAME VARCHAR2(120) NOT NULL,
    ENTRY_ID VARCHAR2(95) NOT NULL,
    TRIGGER_NAME VARCHAR2(200) NOT NULL,
    TRIGGER_GROUP VARCHAR2(200) NOT NULL,
    INSTANCE_NAME VARCHAR2(200) NOT NULL,
    FIRED_TIME NUMBER(13) NOT NULL,
    SCHED_TIME NUMBER(13) NOT NULL,
    PRIORITY NUMBER(13) NOT NULL,
    STATE VARCHAR2(16) NOT NULL,
    JOB_NAME VARCHAR2(200) NULL,
    JOB_GROUP VARCHAR2(200) NULL,
    IS_NONCONCURRENT VARCHAR2(1) NULL,
    REQUESTS_RECOVERY VARCHAR2(1) NULL,
    CONSTRAINT QRTZ_FIRED_TRIGGER_PK PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);
-- 存储少量的有关 Scheduler 的状态信息,和别的 Scheduler 实例(假如是用于一个集群中)
CREATE TABLE qrtz_scheduler_state 
  (
    SCHED_NAME VARCHAR2(120) NOT NULL,
    INSTANCE_NAME VARCHAR2(200) NOT NULL,
    LAST_CHECKIN_TIME NUMBER(13) NOT NULL,
    CHECKIN_INTERVAL NUMBER(13) NOT NULL,
    CONSTRAINT QRTZ_SCHEDULER_STATE_PK PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);
-- 存储程序的悲观锁的信息(假如使用了悲观锁)
CREATE TABLE qrtz_locks
  (
    SCHED_NAME VARCHAR2(120) NOT NULL,
    LOCK_NAME  VARCHAR2(40) NOT NULL, 
    CONSTRAINT QRTZ_LOCKS_PK PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);

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

http://www.voidcn.com/blog/jrn1012/article/p-2176541.html

在做项目时有时候会有定时器任务的功能,比如某某时间应该做什么,多少秒应该怎么样之类的。

spring支持多种定时任务的实现。我们来介绍下使用spring的定时器和使用quartz定时器

  1.我们使用spring-boot作为基础框架,其理念为零配置文件,所有的配置都是基于注解和暴露bean的方式。

  2.使用spring的定时器:

    spring自带支持定时器的任务实现。其可通过简单配置来使用到简单的定时任务。

复制代码
@Component
@Configurable
@EnableScheduling
public class ScheduledTasks{

    @Scheduled(fixedRate = 1000 * 30)
    public void reportCurrentTime(){
        System.out.println ("Scheduling Tasks Examples: The time is now " + dateFormat ().format (new Date ()));
    }

    //每1分钟执行一次
    @Scheduled(cron = "0 */1 *  * * * ")
    public void reportCurrentByCron(){
        System.out.println ("Scheduling Tasks Examples By Cron: The time is now " + dateFormat ().format (new Date ()));
    }

    private SimpleDateFormat dateFormat(){
        return new SimpleDateFormat ("HH:mm:ss");
    }
    
}
复制代码

          没了,没错,使用spring的定时任务就这么简单,其中有几个比较重要的注解:

   @EnableScheduling:标注启动定时任务。

          @Scheduled(fixedRate = 1000 * 30)  定义某个定时任务。

  3.使用quartz实现定时任务。
    Quartz设计者做了一个设计选择来从调度分离开作业。Quartz中的触发器用来告诉调度程序作业什么时候触发。框架提供了一把触发器类型,但两个最常用的是SimpleTrigger和CronTrigger。SimpleTrigger为需要简单打火调度而设计。典型地,如果你需要在给定的时间和重复次数或者两次打火之间等待的秒数打火一个作业,那么SimpleTrigger适合你。另一方面,如果你有许多复杂的作业调度,那么或许需要CronTrigger。
    CronTrigger是基于Calendar-like调度的。当你需要在除星期六和星期天外的每天上午10点半执行作业时,那么应该使用CronTrigger。正如它的名字所暗示的那样,CronTrigger是基于Unix克隆表达式的。

    使用quartz说使用的maven依赖。

    

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>1.8.4</version>
</dependency>

    由于我们使用的是spring-boot框架,其目的是做到零配置文件,所以我们不使用xml文件的配置文件来定义一个定时器,而是使用向spring容器暴露bean的方式。

    向spring容器暴露所必须的bean

    

复制代码
@Configuration
public class SchedledConfiguration {

    // 配置中设定了
    // ① targetMethod: 指定需要定时执行scheduleInfoAction中的simpleJobTest()方法
    // ② concurrent:对于相同的JobDetail,当指定多个Trigger时, 很可能第一个job完成之前,
    // 第二个job就开始了。指定concurrent设为false,多个job不会并发运行,第二个job将不会在第一个job完成之前开始。
    // ③ cronExpression:0/10 * * * * ?表示每10秒执行一次,具体可参考附表。
    // ④ triggers:通过再添加其他的ref元素可在list中放置多个触发器。 scheduleInfoAction中的simpleJobTest()方法
    @Bean(name = "detailFactoryBean")
    public MethodInvokingJobDetailFactoryBean detailFactoryBean(ScheduledTasks scheduledTasks){
        MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean ();
        bean.setTargetObject (scheduledTasks);
        bean.setTargetMethod ("reportCurrentByCron");
        bean.setConcurrent (false);
        return bean;
    }

    @Bean(name = "cronTriggerBean")
    public CronTriggerBean cronTriggerBean(MethodInvokingJobDetailFactoryBean detailFactoryBean){
        CronTriggerBean tigger = new CronTriggerBean ();
        tigger.setJobDetail (detailFactoryBean.getObject ());
        try {
            tigger.setCronExpression ("0/5 * * * * ? ");//每5秒执行一次
        } catch (ParseException e) {
            e.printStackTrace ();
        }
        return tigger;

    }

    @Bean
    public SchedulerFactoryBean schedulerFactory(CronTriggerBean[] cronTriggerBean){
        SchedulerFactoryBean bean = new SchedulerFactoryBean ();
        System.err.println (cronTriggerBean[0]);
        bean.setTriggers (cronTriggerBean);
        return bean;
    }
}
复制代码

    MethodInvokingJobDetailFactoryBean:此工厂主要用来制作一个jobDetail,即制作一个任务。由于我们所做的定时任务根本上讲其实就是执行一个方法。所以用这个工厂比较方便。

      注意:其setTargetObject所设置的是一个对象而不是一个类。

    CronTriggerBean:定义一个触发器。

      注意:setCronExpression:是一个表达式,如果此表达式不合规范,即会抛出异常。

    SchedulerFactoryBean:主要的管理的工厂,这是最主要的一个bean。quartz通过这个工厂来进行对各触发器的管理。

  4.对quartz的封装

    由上面代码可以看出来,此处我们设置的是一个固定的cronExpression,那么,做为项目中使用的话,我们一般是需要其动态设置比如从数据库中取出来。

    其实做法也很简单,我们只需要定义一个Trigger来继承CronTriggerBean。顶用其setCronExpression方法即可。

    那么另外一个问题,如果我们要定义两个定时任务则会比较麻烦,需要先注入一个任务工厂,在注入一个触发器。

       为了减少这样的配置,我们定义了一个抽象的超类来继承CronTriggerBean。

    具体代码如下:

    

复制代码
public abstract class BaseCronTrigger extends CronTriggerBean implements Serializable {

    private static final long serialVersionUID = 1L;

    public void init(){
        // 得到任务
        JobDetail jobdetail = new JobDetail (this.getClass ().getSimpleName (),this.getMyTargetObject ().getClass ());
        this.setJobDetail (jobdetail);
        this.setJobName (jobdetail.getName ());
        this.setName (this.getClass ().getSimpleName ());
        try {
            this.setCronExpression (this.getMyCronExpression ());
        } catch (java.text.ParseException e) {
            e.printStackTrace ();
        }

    }

    public abstract String getMyCronExpression();

    public abstract Job getMyTargetObject();

}
复制代码

    其init()方法,来为这个触发器绑定任务。其任务为一个Job类型的,也就是说其执行的任务为实现了Job接口的类,这个任务会有一个execute()方法,来执行任务题。

    

复制代码
public class ScheduledTasks implements Job {
   
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException{
        System.out.println ("Scheduling Tasks Examples By Cron: The time is now " + dateFormat ().format (new Date ()));
    }

   private SimpleDateFormat dateFormat(){
        return new SimpleDateFormat ("HH:mm:ss");
    }
}
复制代码

    为了给触发器添加任务,我们需要在子类中调用init()方法,由于spring容器注入时是使用的空参的构造函数,所以我们在此构造函数中调用init()方法。

    

复制代码
@Component
public class InitializingCronTrigger extends BaseCronTrigger implements Serializable {

    private static final long    serialVersionUID = 1L;

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    public InitializingCronTrigger() {
        init ();
    }

    @Override
    public String getMyCronExpression(){
        return "0/5 * * * * ?";
    }

    @Override
    public Job getMyTargetObject(){
        return new ScheduledTasks ();
    }

    public void parse(){
        try {
            schedulerFactoryBean.getObject ().pauseAll ();
        } catch (SchedulerException e) {
            e.printStackTrace ();
        }
    }

}
复制代码

    此时我们只需要在配置类中加入一个配置就可以了。

    

复制代码
  @Bean
    public SchedulerFactoryBean schedulerFactory(CronTriggerBean[] cronTriggerBean){
        SchedulerFactoryBean bean = new SchedulerFactoryBean ();
        System.err.println (cronTriggerBean[0]);
        bean.setTriggers (cronTriggerBean);

        return bean;
    }
复制代码

  4.介绍一个cronExpression表达式。

    这一部分是摘抄的:

      

字段 允许值 允许的特殊字符
  0-59   , - * /
  0-59   , - * /
小时   0-23   , - * /
日期   1-31   , - *   / L W C
月份   1-12 或者 JAN-DEC   , - * /
星期   1-7 或者 SUN-SAT   , - *   / L C #
年(可选)   留空, 1970-2099   , - * /

  
如上面的表达式所示: 

“*”字符被用来指定所有的值。如:”*“在分钟的字段域里表示“每分钟”。 

“-”字符被用来指定一个范围。如:“10-12”在小时域意味着“10点、11点、12点”。
 
“,”字符被用来指定另外的值。如:“MON,WED,FRI”在星期域里表示”星期一、星期三、星期五”. 

“?”字符只在日期域和星期域中使用。它被用来指定“非明确的值”。当你需要通过在这两个域中的一个来指定一些东西的时候,它是有用的。看下面的例子你就会明白。 


“L”字符指定在月或者星期中的某天(最后一天)。即“Last ”的缩写。但是在星期和月中“L”表示不同的意思,如:在月子段中“L”指月份的最后一天-1月31日,2月28日,如果在星期字段中则简单的表示为“7”或者“SAT”。如果在星期字段中在某个value值得后面,则表示“某月的最后一个星期value”,如“6L”表示某月的最后一个星期五。

“W”字符只能用在月份字段中,该字段指定了离指定日期最近的那个星期日。

“#”字符只能用在星期字段,该字段指定了第几个星期value在某月中


每一个元素都可以显式地规定一个值(如6),一个区间(如9-12),一个列表(如9,11,13)或一个通配符(如*)。“月份中的日期”和“星期中的日期”这两个元素是互斥的,因此应该通过设置一个问号(?)来表明你不想设置的那个字段。表7.1中显示了一些cron表达式的例子和它们的意义:

表达式

 意义
"0 0 12 * * ?"   每天中午12点触发
"0 15 10 ? * *"   每天上午10:15触发
"0 15 10 * * ?"   每天上午10:15触发
"0 15 10 * * ? *"   每天上午10:15触发
"0 15 10 * * ? 2005"   2005年的每天上午10:15触发
"0 * 14 * * ?"   在每天下午2点到下午2:59期间的每1分钟触发
"0 0/5 14 * * ?"   在每天下午2点到下午2:55期间的每5分钟触发
"0 0/5 14,18 * * ?"   在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
"0 0-5 14 * * ?"   在每天下午2点到下午2:05期间的每1分钟触发
"0 10,44 14 ? 3 WED"   每年三月的星期三的下午2:10和2:44触发
"0 15 10 ? * MON-FRI"   周一至周五的上午10:15触发
"0 15 10 15 * ?"   每月15日上午10:15触发
"0 15 10 L * ?"   每月最后一日的上午10:15触发
"0 15 10 ? * 6L"   每月的最后一个星期五上午10:15触发 
"0 15 10 ? * 6L 2002-2005"   2002年至2005年的每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6#3"   每月的第三个星期五上午10:15触发

            每天早上6点 0 6 * * * 

            每两个小时 0 */2 * * * 

            晚上11点到早上8点之间每两个小时,早上八点 0 23-7/2,8 * * * 

                                                     每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点 0 11 4 * 1-3 

            1月1日早上4点 0 4 1 1 *

http://www.cnblogs.com/lic309/p/4089633.html

原文地址:https://www.cnblogs.com/softidea/p/6670506.html