背景:在这篇文章之前写了一篇很浅显的quartz的使用,对于想要了解quartz的使用的话可能算是能用了,但是如果项目部署在多个服务器上面的话,那么就需要考虑到集群的问题,所以做完了基本的定时任务之后,师兄就给我新的任务:quartz的集群任务。
集群:集群是一组相互独立的、通过高速网络互联的计算机,它们构成了一个组,并以单一系统的模式加以管理。一个客户与集群相互作用时,集群像是一个独立的服务器。集群配置是用于提高可用性和可缩放性。
→ 。→ 虽然说这个概念对我们的任务来说没什么用,但是最起码要知道你要面对的坑是个什么样的坑
进入正题吧,说说看集群任务到底该怎么做:
步骤的话应该有:
1.导包,这个是最起码的东西,没有舞台,你在哪儿跳舞呢?
怎么搞,我就不说了,在上一篇文章中有介绍过
quartz的引导包
或者可以去官方网站去查询下载
quartz官网
这个步骤可能大家不觉得有问题哟,但是也请不要忽略!!!
那么问题来了,为什么呢?
往下看吧。
2.配置quartz.properties文件
#==============================================================
#Configure Main Scheduler Properties
#==============================================================
org.quartz.scheduler.instanceName = quartzScheduler
org.quartz.scheduler.instanceId = AUTO
#==============================================================
#Configure ThreadPool
#==============================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
#==============================================================
#Configure JobStore
#==============================================================
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 15000
org.quartz.jobStore.dataSource = myDS
#==============================================================
#Configure DataSource (数据库连接信息)
#==============================================================
org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc\:mysql\://localhost\:3306/lemon?useUnicode\=true&characterEncoding\=UTF-8
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password =
org.quartz.dataSource.myDS.maxConnections =30
如果不涉及集群任务的话,quartz的配置文件是可有可无的。
也许会有人说:必须的!
不好意思,亲自试试就知道……
But想要配置集群任务的话,就必须需要配置文件,当然我们关心的肯定是配置文件的属性值:
关于其中的参数分析的话有文章比我写的好 ——> 属性了解请戳
其中比较关键的额就是ThreadPool和JobStore的这些配置,这里设置的参数一般不会变动。
其中org.quartz.jobStore.isClustered = true 的意思是打开集群特性,我想关键的地方就是这里吧。
这个文件呢不要乱放,找不到你就头大了
所以说如果项目是非maven就放在src目录下,maven项目就放在resource目录下
3.前两步应该不会有什么问题的吧
是的
不会
if("you have trouble" == true){
System.out.println("How to do?");
}
开个玩笑
实现集群任务的关键步骤应该是第三步吧,这里的业务层如果涉及到持久化问题,那么被调度的任务必须被序列化
开始我也很懵逼,该怎么解决序列化的问题
问了百度和Google之后,发现实现的方法有两种:
①重写MethodInvokingJobDetailFactoryBean方法,因为这个方法在quartz包中是没有被序列化,矛盾就在这里:集群时候被schedulerFactoryBean调用的类必须是被序列化的,但是上述的包内的方法是没有被序列化的;
②被调用的任务类需要继承QuartzJobBean,这个方法不需要序列化,要是你问我怎么知道的,至于这个原因么,我还是不乱说的好,因为官方就是这么给的,希望大神指点。
说说我的情况:我开始是重写这个方法的,至于怎么重写它,各位,我只想奉劝一句:不要入坑
所以说第二种方法还是靠谱一点,具体的代码实现
public class SynDingUserToEntityTask extends QuartzJobBean {
private DoSynDingUserToEntity doSynDingUserToEntity;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try {
SchedulerContext schedulerContext = jobExecutionContext.getScheduler().getContext();
doSynDingUserToEntity = (DoSynDingUserToEntity) schedulerContext.get("doSynDingUserToEntity");
doSynDingUserToEntity.doSynDingUserToEntity();
} catch (SchedulerException e) {
log.error("同步用户信息到entity失败");
e.printStackTrace();
}
}
}
重写executeInternal()方法,具体的业务操作就在方法内部实现。
这里会有坑的地方在哪儿呢:
SchedulerContext schedulerContext = jobExecutionContext.getScheduler().getContext();
doSynDingUserToEntity = (DoSynDingUserToEntity) schedulerContext.get("doSynDingUserToEntity");
上面代码的这一部分,也就是想要利用其他的实体类,会通过这种方法获取
另外在配置文件中,需要将该实体通过bean注入到schedulerFactoryBean中
<bean id="QuartzDoSynDingUserToEntity" class="com.mhc.fiat.syn.syndo.DoSynDingUserToEntity"/>
<bean id="schedulerFactoryBean" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="configLocation" value="classpath:quartz.properties"/>
<property name="overwriteExistingJobs" value="true"/>
<property name="applicationContextSchedulerContextKey" value="applicationContext"/>
<property name="schedulerContextAsMap">
<map>
<description>shcedulerContextAsMap</description>
<entry key="doSynDingUserToEntity" value-ref="QuartzDoSynDingUserToEntity"/>
<entry key="doSyncDingToStruct" value-ref="QuartzDoSyncDingToStruct"/>
</map>
</property>
<property name="triggers">
<list>
<ref bean="updateUserInfoToEntityTask"/>
</list>
</property>
</bean>
也就是说呢:通过@Autowired或者创建对象的方法你都会遇到一个问题就是这些对象全部都为null。
完成这些部分之后,quartz还是不能够使用的;
因为;
你要添加11张表之后才能够使用,因为我是用的quartz2.2.2版本,所以这里就是版本的SQL
#
# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
#
# PLEASE consider using mysql with innodb tables to avoid locking issues
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
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;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;
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)
);
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)
);
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)
);
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(200) 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)
);
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)
);
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),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
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)
);
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
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)
);
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)
);
CREATE TABLE QRTZ_LOCKS
(
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);
commit;
当然版本不同需要的数据库文件也是不一样的,可以在quartz包下面的docs中找到对应的sql文件。
完成这三步的话,quartz就能够正常使用了,因为在实习阶段,所以这些东西在学校内没有用到过,能够在项目中运用,估计之后也会有和我一样的童鞋,遇到这些问题的时候也会郁闷吧,这里是顺利的执行状况,其实中间还会有很多问题。只能说实际情况还是找办法解决。
其中有一个问题现在也没有搞清楚:在继承QuartzJobBean的任务类中,获取到的JdbcTemplate对象可以执行SQL语句,但是每次插入数据之后会自动回滚,将插入的数据又清零,希望有高手遇到类似情况的话,指点指点。