Spring&Quartz使用資料庫叢集配置(MySQL/SQLServer/Oracle)

colorandsong發表於2014-10-30

Spring框架對Quartz定時任務做了很好的整合,但針對多臺伺服器同時使用定時任務時,此時必須要做資料庫的叢集,以防止重複排程,一般步驟如下:

一、配置排程器、觸發器、job

1、排程器

<bean name="quartzScheduler" lazy-init="false"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="ds" />
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<property name="configLocation" value="classpath:quartz.properties" />
<property name="triggers">
<list>
<ref bean="trigger" />
</list>
</property>
</bean>

2、配置觸發器

<bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="jobDetail" />
<property name="cronExpression" value="0 0 0/1 * * ?" />
</bean>

3、配置job

<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.xxx.ClassName" />
</bean>


二、配置quartz.properties檔案

org.quartz.scheduler.instanceName = MyScheduler
org.quartz.scheduler.instanceId = AUTO
orgorg.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.jobStore.misfireThreshold = 60000
orgorg.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
orgorg.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.maxMisfiresToHandleAtATime=10
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 1000
org.quartz.jobStore.selectWithLockSQL=select * from {0}LOCKS UPDLOCK WHERE LOCK_NAME=?



三、新建資料庫表

共12張表,MySQL和SQLServer有點區別,主要在於大欄位的區別,MySQL用了clob的地方,SQLServer要用image欄位,Oracle則要用blob欄位,除此之外大致相同。

1、MySQL的SQL語句如下:

CREATE TABLE QRTZ_JOB_DETAILS 

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_VOLATILE VARCHAR(1) NOT NULL, 
IS_STATEFUL VARCHAR(1) NOT NULL, 
REQUESTS_RECOVERY VARCHAR(1) NOT NULL, 
JOB_DATA BLOB NULL, 
PRIMARY KEY (JOB_NAME,JOB_GROUP) 
); 

CREATE TABLE QRTZ_JOB_LISTENERS 

JOB_NAME VARCHAR(200) NOT NULL, 
JOB_GROUP VARCHAR(200) NOT NULL, 
JOB_LISTENER VARCHAR(200) NOT NULL, 
PRIMARY KEY (JOB_NAME,JOB_GROUP,JOB_LISTENER), 
FOREIGN KEY (JOB_NAME,JOB_GROUP) 
REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP) 
); 

CREATE TABLE QRTZ_TRIGGERS 

TRIGGER_NAME VARCHAR(200) NOT NULL, 
TRIGGER_GROUP VARCHAR(200) NOT NULL, 
JOB_NAME VARCHAR(200) NOT NULL, 
JOB_GROUP VARCHAR(200) NOT NULL, 
IS_VOLATILE VARCHAR(1) 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 (TRIGGER_NAME,TRIGGER_GROUP), 
FOREIGN KEY (JOB_NAME,JOB_GROUP) 
REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP) 
); 

CREATE TABLE QRTZ_SIMPLE_TRIGGERS 

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(7) NOT NULL, 
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP), 
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) 
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP) 
); 

CREATE TABLE QRTZ_CRON_TRIGGERS 

TRIGGER_NAME VARCHAR(200) NOT NULL, 
TRIGGER_GROUP VARCHAR(200) NOT NULL, 
CRON_EXPRESSION VARCHAR(200) NOT NULL, 
TIME_ZONE_ID VARCHAR(80), 
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP), 
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) 
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP) 
); 

CREATE TABLE QRTZ_BLOB_TRIGGERS 

TRIGGER_NAME VARCHAR(200) NOT NULL, 
TRIGGER_GROUP VARCHAR(200) NOT NULL, 
BLOB_DATA BLOB NULL, 
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP), 
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) 
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP) 
); 

CREATE TABLE QRTZ_TRIGGER_LISTENERS 

TRIGGER_NAME VARCHAR(200) NOT NULL, 
TRIGGER_GROUP VARCHAR(200) NOT NULL, 
TRIGGER_LISTENER VARCHAR(200) NOT NULL, 
PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_LISTENER), 
FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) 
REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP) 
); 


CREATE TABLE QRTZ_CALENDARS 

CALENDAR_NAME VARCHAR(200) NOT NULL, 
CALENDAR BLOB NOT NULL, 
PRIMARY KEY (CALENDAR_NAME) 
); 



CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS 

TRIGGER_GROUP VARCHAR(200) NOT NULL, 
PRIMARY KEY (TRIGGER_GROUP) 
); 

CREATE TABLE QRTZ_FIRED_TRIGGERS 

ENTRY_ID VARCHAR(95) NOT NULL, 
TRIGGER_NAME VARCHAR(200) NOT NULL, 
TRIGGER_GROUP VARCHAR(200) NOT NULL, 
IS_VOLATILE VARCHAR(1) NOT NULL, 
INSTANCE_NAME VARCHAR(200) NOT NULL, 
FIRED_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_STATEFUL VARCHAR(1) NULL, 
REQUESTS_RECOVERY VARCHAR(1) NULL, 
PRIMARY KEY (ENTRY_ID) 
); 

CREATE TABLE QRTZ_SCHEDULER_STATE 

INSTANCE_NAME VARCHAR(200) NOT NULL, 
LAST_CHECKIN_TIME BIGINT(13) NOT NULL, 
CHECKIN_INTERVAL BIGINT(13) NOT NULL, 
PRIMARY KEY (INSTANCE_NAME) 
); 

CREATE TABLE QRTZ_LOCKS 

LOCK_NAME VARCHAR(40) NOT NULL, 
PRIMARY KEY (LOCK_NAME) 
); 

2、SQLServer的語句如下:

CREATE TABLE QRTZ_BLOB_TRIGGERS(
[TRIGGER_NAME] [varchar](200) NOT NULL,
[TRIGGER_GROUP] [varchar](200) NOT NULL,
[BLOB_DATA] [image] NULL
)

CREATE TABLE QRTZ_CALENDARS(
[CALENDAR_NAME] [varchar](200) NOT NULL,
[CALENDAR] [image] NOT NULL
)




CREATE TABLE QRTZ_CRON_TRIGGERS(
[TRIGGER_NAME] [varchar](200) NOT NULL,
[TRIGGER_GROUP] [varchar](200) NOT NULL,
[CRON_EXPRESSION] [varchar](120) NOT NULL,
[TIME_ZONE_ID] [varchar](80) NULL
)


CREATE TABLE QRTZ_FIRED_TRIGGERS(
[ENTRY_ID] [varchar](95) NOT NULL,
[TRIGGER_NAME] [varchar](200) NOT NULL,
[TRIGGER_GROUP] [varchar](200) NOT NULL,
[IS_VOLATILE] [varchar](1) NOT NULL,
[INSTANCE_NAME] [varchar](200) NOT NULL,
[FIRED_TIME] [bigint] NOT NULL,
[PRIORITY] [int] NOT NULL,
[STATE] [varchar](16) NOT NULL,
[JOB_NAME] [varchar](200) NULL,
[JOB_GROUP] [varchar](200) NULL,
[IS_STATEFUL] [varchar](1) NULL,
[REQUESTS_RECOVERY] [varchar](1) NULL
)

CREATE TABLE QRTZ_JOB_DETAILS(
[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_VOLATILE] [varchar](1) NOT NULL,
[IS_STATEFUL] [varchar](1) NOT NULL,
[REQUESTS_RECOVERY] [varchar](1) NOT NULL,
[JOB_DATA] [image] NULL
)

CREATE TABLE QRTZ_JOB_LISTENERS(
[JOB_NAME] [varchar](200) NOT NULL,
[JOB_GROUP] [varchar](200) NOT NULL,
[JOB_LISTENER] [varchar](200) NOT NULL
)

CREATE TABLE QRTZ_LOCKS(
[LOCK_NAME] [varchar](40) NOT NULL
)

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS(
[TRIGGER_GROUP] [varchar](200) NOT NULL
)

CREATE TABLE QRTZ_SCHEDULER_STATE(
[INSTANCE_NAME] [varchar](200) NOT NULL,
[LAST_CHECKIN_TIME] [bigint] NOT NULL,
[CHECKIN_INTERVAL] [bigint] NOT NULL


CREATE TABLE QRTZ_SIMPLE_TRIGGERS(
[TRIGGER_NAME] [varchar](200) NOT NULL,
[TRIGGER_GROUP] [varchar](200) NOT NULL,
[REPEAT_COUNT] [bigint] NOT NULL,
[REPEAT_INTERVAL] [bigint] NOT NULL,
[TIMES_TRIGGERED] [bigint] NOT NULL
)

CREATE TABLE QRTZ_TRIGGER_LISTENERS(
[TRIGGER_NAME] [varchar](200) NOT NULL,
[TRIGGER_GROUP] [varchar](200) NOT NULL,
[TRIGGER_LISTENER] [varchar](200) NOT NULL
)

CREATE TABLE QRTZ_TRIGGERS(
[TRIGGER_NAME] [varchar](200) NOT NULL,
[TRIGGER_GROUP] [varchar](200) NOT NULL,
[JOB_NAME] [varchar](200) NOT NULL,
[JOB_GROUP] [varchar](200) NOT NULL,
[IS_VOLATILE] [varchar](1) NOT NULL,
[DESCRIPTION] [varchar](250) NULL,
[NEXT_FIRE_TIME] [bigint] NULL,
[PREV_FIRE_TIME] [bigint] NULL,
[PRIORITY] [int] NULL,
[TRIGGER_STATE] [varchar](16) NOT NULL,
[TRIGGER_TYPE] [varchar](8) NOT NULL,
[START_TIME] [bigint] NOT NULL,
[END_TIME] [bigint] NULL,
[CALENDAR_NAME] [varchar](200) NULL,
[MISFIRE_INSTR] [smallint] NULL,
[JOB_DATA] [image] NULL
)


3、Oracle的語句如下:

CREATE TABLE QRTZ_BLOB_TRIGGERS 
(
  TRIGGER_NAME VARCHAR2(200 BYTE) NOT NULL 
, TRIGGER_GROUP VARCHAR2(200 BYTE) NOT NULL 
, BLOB_DATA BLOB 
, CONSTRAINT SYS_C00429109 PRIMARY KEY 
  (
    TRIGGER_NAME 
  , TRIGGER_GROUP 
  )
  ENABLE 





CREATE TABLE QRTZ_CALENDARS 
(
  CALENDAR_NAME VARCHAR2(200 BYTE) NOT NULL 
, CALENDAR BLOB NOT NULL 
, CONSTRAINT SYS_C00429112 PRIMARY KEY 
  (
    CALENDAR_NAME 
  )
  ENABLE 
)




CREATE TABLE QRTZ_CRON_TRIGGERS 
(
  TRIGGER_NAME VARCHAR2(200 BYTE) NOT NULL 
, TRIGGER_GROUP VARCHAR2(200 BYTE) NOT NULL 
, CRON_EXPRESSION VARCHAR2(120 BYTE) NOT NULL 
, TIME_ZONE_ID VARCHAR2(80 BYTE) 
, CONSTRAINT SYS_C00429116 PRIMARY KEY 
  (
    TRIGGER_NAME 
  , TRIGGER_GROUP 
  )
  ENABLE 
)




CREATE TABLE QRTZ_FIRED_TRIGGERS 
(
  ENTRY_ID VARCHAR2(95 BYTE) NOT NULL 
, TRIGGER_NAME VARCHAR2(200 BYTE) NOT NULL 
, TRIGGER_GROUP VARCHAR2(200 BYTE) NOT NULL 
, IS_VOLATILE VARCHAR2(1 BYTE) NOT NULL 
, INSTANCE_NAME VARCHAR2(200 BYTE) NOT NULL 
, FIRED_TIME NUMBER(13, 0) NOT NULL 
, PRIORITY NUMBER(13, 0) NOT NULL 
, STATE VARCHAR2(16 BYTE) NOT NULL 
, JOB_NAME VARCHAR2(200 BYTE) 
, JOB_GROUP VARCHAR2(200 BYTE) 
, IS_STATEFUL VARCHAR2(1 BYTE) 
, REQUESTS_RECOVERY VARCHAR2(1 BYTE) 
, CONSTRAINT SYS_C00429125 PRIMARY KEY 
  (
    ENTRY_ID 
  )
  ENABLE 





CREATE TABLE QRTZ_JOB_DETAILS 
(
  JOB_NAME VARCHAR2(200 BYTE) NOT NULL 
, JOB_GROUP VARCHAR2(200 BYTE) NOT NULL 
, DESCRIPTION VARCHAR2(250 BYTE) 
, JOB_CLASS_NAME VARCHAR2(250 BYTE) NOT NULL 
, IS_DURABLE VARCHAR2(1 BYTE) NOT NULL 
, IS_VOLATILE VARCHAR2(1 BYTE) NOT NULL 
, IS_STATEFUL VARCHAR2(1 BYTE) NOT NULL 
, REQUESTS_RECOVERY VARCHAR2(1 BYTE) NOT NULL 
, JOB_DATA BLOB 
, CONSTRAINT SYS_C00429133 PRIMARY KEY 
  (
    JOB_NAME 
  , JOB_GROUP 
  )
  ENABLE 





CREATE TABLE QRTZ_JOB_LISTENERS 
(
  JOB_NAME VARCHAR2(200 BYTE) NOT NULL 
, JOB_GROUP VARCHAR2(200 BYTE) NOT NULL 
, JOB_LISTENER VARCHAR2(200 BYTE) NOT NULL 
, CONSTRAINT SYS_C00429137 PRIMARY KEY 
  (
    JOB_NAME 
  , JOB_GROUP 
  , JOB_LISTENER 
  )
  ENABLE 





CREATE TABLE QRTZ_LOCKS 
(
  LOCK_NAME VARCHAR2(40 BYTE) NOT NULL 
, CONSTRAINT SYS_C00429139 PRIMARY KEY 
  (
    LOCK_NAME 
  )
  ENABLE 





CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS 
(
  TRIGGER_GROUP VARCHAR2(200 BYTE) NOT NULL 
, CONSTRAINT SYS_C00429141 PRIMARY KEY 
  (
    TRIGGER_GROUP 
  )
  ENABLE 
)




CREATE TABLE QRTZ_SCHEDULER_STATE 
(
  INSTANCE_NAME VARCHAR2(200 BYTE) NOT NULL 
, LAST_CHECKIN_TIME NUMBER(13, 0) NOT NULL 
, CHECKIN_INTERVAL NUMBER(13, 0) NOT NULL 
, CONSTRAINT SYS_C00429145 PRIMARY KEY 
  (
    INSTANCE_NAME 
  )
  ENABLE 





CREATE TABLE QRTZ_SIMPLE_TRIGGERS 
(
  TRIGGER_NAME VARCHAR2(200 BYTE) NOT NULL 
, TRIGGER_GROUP VARCHAR2(200 BYTE) NOT NULL 
, REPEAT_COUNT NUMBER(7, 0) NOT NULL 
, REPEAT_INTERVAL NUMBER(12, 0) NOT NULL 
, TIMES_TRIGGERED NUMBER(10, 0) NOT NULL 
, CONSTRAINT SYS_C00429151 PRIMARY KEY 
  (
    TRIGGER_NAME 
  , TRIGGER_GROUP 
  )
  ENABLE 





CREATE TABLE QRTZ_TRIGGER_LISTENERS 
(
  TRIGGER_NAME VARCHAR2(200 BYTE) NOT NULL 
, TRIGGER_GROUP VARCHAR2(200 BYTE) NOT NULL 
, TRIGGER_LISTENER VARCHAR2(200 BYTE) NOT NULL 
, CONSTRAINT SYS_C00429164 PRIMARY KEY 
  (
    TRIGGER_NAME 
  , TRIGGER_GROUP 
  , TRIGGER_LISTENER 
  )
  ENABLE 





CREATE TABLE QRTZ_TRIGGERS 
(
  TRIGGER_NAME VARCHAR2(200 BYTE) NOT NULL 
, TRIGGER_GROUP VARCHAR2(200 BYTE) NOT NULL 
, JOB_NAME VARCHAR2(200 BYTE) NOT NULL 
, JOB_GROUP VARCHAR2(200 BYTE) NOT NULL 
, IS_VOLATILE VARCHAR2(1 BYTE) NOT NULL 
, DESCRIPTION VARCHAR2(250 BYTE) 
, NEXT_FIRE_TIME NUMBER(13, 0) 
, PREV_FIRE_TIME NUMBER(13, 0) 
, PRIORITY NUMBER(13, 0) 
, TRIGGER_STATE VARCHAR2(16 BYTE) NOT NULL 
, TRIGGER_TYPE VARCHAR2(8 BYTE) NOT NULL 
, START_TIME NUMBER(13, 0) NOT NULL 
, END_TIME NUMBER(13, 0) 
, CALENDAR_NAME VARCHAR2(200 BYTE) 
, MISFIRE_INSTR NUMBER(2, 0) 
, JOB_DATA BLOB 
, CONSTRAINT SYS_C00429160 PRIMARY KEY 
  (
    TRIGGER_NAME 
  , TRIGGER_GROUP 
  )
  ENABLE 
)


四、初始化資料

無論是MysqL/SQLServer/Oracle,都需要初始化QRTZ_LOCKS表,語句如下:

INSERT INTO QRTZ_LOCKS values('TRIGGER_ACCESS'); 
INSERT INTO QRTZ_LOCKS values('JOB_ACCESS'); 
INSERT INTO QRTZ_LOCKS values('CALENDAR_ACCESS'); 
INSERT INTO QRTZ_LOCKS values('STATE_ACCESS'); 
INSERT INTO QRTZ_LOCKS values('MISFIRE_ACCESS'); 


五、實現JobManage類管理配置檔案

Spring配置檔案有修改時(一般是定時任務有修改),需要將修改後的Spring配置檔案更新到資料庫,這時候就需要用JobManage類來管理了,Spring容器初始化時用Schedule物件來重新排程,如下:

/**
 * 
 * @類名: JobManager.java 
 * @描述:job管理類,每當配置檔案修改時重新管理配置檔案到資料庫,並且初始化時獲取access_token到資料庫
 * @作者: mxyanx
 * @修改日期: 2014年9月28日
 */
@Component
public class JobManager {
    private static final Logger logger = Logger.getLogger(JobManager.class);
@Autowired
private Scheduler scheduler;
@Autowired
private CronTriggerInfoDao cronTriggerInfoDao;
@Autowired
private AccessTokenService accessTokenService;
@Autowired
@Qualifier("trigger")
        private Trigger trigger;
@PostConstruct
public void start() throws SchedulerException{
   List<CronTriggerInfo> cronTriggersList = this.cronTriggerInfoDao.getCronTriggerList();
   for(CronTriggerInfo cronTriggerInfo : cronTriggersList){
       if(cronTriggerInfo.getTriggerName().equalsIgnoreCase("trigger")){
           scheduler.rescheduleJob(cronTriggerInfo.getTriggerName(), Scheduler.DEFAULT_GROUP, trigger);
       }
            }
   this.accessTokenService.processAccessToken();
}
}


值得注意的是,這裡的

@Autowired
private AccessTokenService accessTokenService;

在初始化時能夠被注入進來,是因為在Spring的配置檔案中做了處理,詳見本部落格另一篇文章《Spring使用Quartz定時排程Job無法Autowired注入Service的解決方案》。

相關文章