一:说明
1. 使用spring 支持quartz 的方式实现定时任务
2. 使用mysql做quartz的集群
二:准备工作
1. 安装mqyl(过程略,我的mysql ip为:192.168.75.128), 创建数据库quartz
2. 下载quartz相关包(http://www.quartz-scheduler.org/downloads/destination?name=quartz-1.8.6.tar.gz&bucket=tcdistributions&file=quartz-1.8.6.tar.gz),
解压后在 docs\dbTables 目录下有相关数据库的sql,用此sql脚本在quartz数据库中执行,创建表/索引(1.8.6和2.x sql脚本不同,这里使用的quartz是1.8.6,因为 spring3.x 不支持quartz 2.x 的版本)
三:demo实现
1. 使用maven管理依赖,依赖如下:
UTF-8
3.2.3.RELEASE
org.springframework
spring-context
${spring.version}
org.springframework
spring-context-support
${spring.version}
org.springframework
spring-expression
${spring.version}
org.springframework
spring-tx
${spring.version}
org.springframework
spring-test
${spring.version}
compile
2. applicationContext.xml 配置
org.gjt.mm.mysql.Driver
jdbc:mysql://192.168.75.128:3306/quartz?characterEncoding=utf8
root
123456
3. quartz.properties 配置
#属性可为任何值,用在 JDBC JobStore 中来唯一标识实例,但是所有集群节点中必须相同。
org.quartz.scheduler.instanceName = HumsScheduler
#为 AUTO即可,基于主机名和时间戳来产生实例 ID。
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
#将任务持久化到数据中。因为集群中节点依赖于数据库来传播 Scheduler 实例的状态,你只能在使用 JDBC JobStore 时应用 Quartz 集群。这意味着你必须使用 JobStoreTX 或是 JobStoreCMT 作为 Job 存储;你不能在集群中使用 RAMJobStore。
orgorg.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
orgorg.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
#jobStore处理未按时触发的Job的数量
org.quartz.jobStore.maxMisfiresToHandleAtATime=10
#告诉了 Scheduler 实例要它参与到一个集群当中。这一属性会贯穿于调度框架的始终,用于修改集群环境中操作的默认行为。
org.quartz.jobStore.isClustered = true
#定义了Scheduler实例检入到数据库中的频率(单位:毫秒)。Scheduler 检查是否其他的实例到了它们应当检入的时候未检入;这能指出一个失败的 Scheduler 实例,且当前 Scheduler 会以此来接管任何执行失败并可恢复的 Job。通过检入操作,Scheduler 也会更新自身的状态记录。clusterChedkinInterval 越小,Scheduler 节点检查失败的 Scheduler 实例就越频繁。默认值是 15000 (即15 秒)。
org.quartz.jobStore.clusterCheckinInterval = 15000
4. job com.mas.db.JobHello 的实现(注意job实现类的说明)
/**
* 1. 继承 QuartzJobBean
* 2. 如果任务处理时间大于job触发频率时间,那么任务会并行处理,
* 实现 StatefulJob后job就会在一次任务没有处理完就不会进行下一次任务(任务的串行处理)
*
*/
public class JobHello extends QuartzJobBean implements StatefulJob {
@Override
protected void executeInternal(JobExecutionContext arg0)
throws JobExecutionException {
try {
//任务处理
System.out.println("job hello"+System.currentTimeMillis());
//模拟任务处理时间大于job触发频率
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//任务处理 System.out.println("job hello"+System.currentTimeMillis()); //模拟任务处理时间大于job触发频率 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } }}
5. 测试1. 可以起多个main方法进行测试(HelloTest 和 HelloTest2),多个main方法同时起动后只有一个job在执行,当停止一个main线程后,等到Scheduler实例检入到数据库中的频率(quartz.properties 是配置的org.quartz.jobStore.clusterCheckinInterval ) 过后,就会有一个线程接着执行这个job
public class HelloTest {
public static void main(String[] args) {
//定时任务开启模拟
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
}
}
2.UpdateQuartzTest 测试类中是对 trigger的操作测试,如:修改触发频率、暂停、重启,获取trigger的运行状态,获取全部的trigger。如需更多对trigger或者job的操作可查看org.quartz.impl.StdScheduler 源码。
注意:修改trigger 的触发频率后,再暂停,然后重新启动;发现trigger是触发频率和初始化的时候相同, 说明:修改trigger触发频率只是对运行中的trigger有效,如果trigger重新启动则trigger触发频率还原为配置的频率
四:demo源码,在test中有两个测试类(
HelloTest 和 HelloTest2
模拟部属两个集群。
UpdateQuartzTest
中为操作trigger是测试,测试时需要启动HelloTest或者HelloTest2,两者都启动亦可
).
完整代码:http://download.csdn.net/detail/convict_eva/9626160
六:Terracotta公司有个脱离关系型数据库实现集群解决方案的方法
http://www.terracotta.org/products/quartz-scheduler
备注:定时器时间配置
1.秒(0–59)
2.分钟(0–59)
3.小时(0–23)
4.月份中的日期(1–31)
5.月份(1–12或JAN–DEC)
6.星期中的日期(1–7或SUN–SAT)
7.年份(1970–2099)
示例:
"0/10 * * * * ?" 每10秒触发
"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触发
说明:
星号(*):可用在所有字段中,表示对应时间域的每一个时刻,例如,*在分钟字段时,表示“每分钟”;
问号(?):该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符;
减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;
逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;
斜杠(/):x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;