为什么使用quartz集群? 在服务部署一个节点的时候,quartz任务是可以正常运行的。但是如果你业务上需要部署2个或者以上的集群时,就需要处理集群之间的定时任务执行问题了。而quartz集群就是为了解决这个问题的。前提是集群的时间同步,以及共用同一个数据库。
1.导入数据库表 以mysql为例,下载quartz发行版,在/docs/dbTables下找到tables_mysql_innodb.sql。导入数据结构到数据库内。 使用tables_mysql.sql的话,由于没有指定使用innodB引擎,在一些默认使用MYISAM的数据库实例内可能会报错。
注意事项:
修改SQL: TYPE=InnoDB –> ENGINE=InnoDB
2.项目中加入配置文件quartz.properties #============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = ClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.skipUpdateCheck = true
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 15000
3.增加applicationContext-quartz.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?xml version="1.0"  encoding="UTF-8" ?> <beans  xmlns ="http://www.springframework.org/schema/beans"  xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"         xmlns:util ="http://www.springframework.org/schema/util"         xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd                          http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"        default-lazy-init ="false" >     <description > Quartz的定时集群任务配置</description >      <bean  id ="quartzDataSource"  class ="org.springframework.jdbc.datasource.SimpleDriverDataSource" >          <property  name ="driverClass"  value ="${db.driver}"  />          <property  name ="url"  value ="${db.url}"  />          <property  name ="username"  value ="${db.user}"  />          <property  name ="password"  value ="${db.pass}"  />      </bean >           <bean  id ="clusterQuartzScheduler"  class ="org.springframework.scheduling.quartz.SchedulerFactoryBean" >                   <property  name ="triggers" >              <list >                  <ref  bean ="testTrigger"  />              </list >          </property >                   <property  name ="configLocation"  value ="classpath:quartz/quartz.properties"  />                   <property  name ="startupDelay"  value ="3"  />                   <property  name ="dataSource"  ref ="quartzDataSource"  />                   <property  name ="applicationContextSchedulerContextKey"  value ="applicationContext"  />          <property  name ="overwriteExistingJobs"  value ="true"  />          <property  name ="jobFactory" >              <bean  class ="com.shenyanchao.quartz.AutoWiringSpringBeanJobFactory" />          </property >       </bean >  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15     <bean  id ="testTrigger"  class ="org.springframework.scheduling.quartz.CronTriggerBean" >          <property  name ="jobDetail"  ref ="testJobDetail"  />          <property  name ="cronExpression"  value ="* 0/10 * * * ?"  />      </bean >           <bean  id ="testJobDetail"  class ="org.springframework.scheduling.quartz.JobDetailBean" >          <property  name ="jobClass"  value ="cn.shenyanchao.quartz.TestTask"  />      </bean >           <util:map  id ="timerJobConfig" >          <entry  key ="nodeName"  value ="default"  />      </util:map >  </beans > 
其中尤其注意,设置overwriteExistingJobs为true,这个选项可以在修改cronExpression之后,能够更新到数据库,否则无法生效。
另外,配置JobFactory使得QuartzJob可以@Autowired注入spring托管的实例。内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public  final  class  AutoWiringSpringBeanJobFactory  extends  SpringBeanJobFactory  implements  ApplicationContextAware  {        private  transient  AutowireCapableBeanFactory beanFactory;         public  void  setApplicationContext (final  ApplicationContext context)  {             beanFactory = context.getAutowireCapableBeanFactory();         }         @Override          protected  Object createJobInstance (final  TriggerFiredBundle bundle)  throws  Exception {             final  Object  job  =  super .createJobInstance(bundle);             beanFactory.autowireBean(job);             return  job;         }     } 
4. 如何写JOB? 1 2 3 4 5 6 7 8 9 10 11 12 @Component public  class  TestTask  extends  QuartzJobBean  {    @Autowired      private  UserService userService;     @Override      protected  void  executeInternal (JobExecutionContext context)  throws  JobExecutionException {         System.out.println(userService.findByName("shenyanchao" ).getEmail());     } } 
由于使用MethodInvokingFactoryBean总是报seriziable错误,因此本例使用的是JobDetailBean。那这也意味着要继承QuartzJobBean。同时由于配置了JobFactory,使得可以直接注入UserService等实例。
5.quartz在mysql5.6下报错 1 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'OPTION SQL_SELECT_LIMIT=5' at line 1 
这个错误是由于mysql connector的版本太低导致的,可以通过升级版本来解决。 参见http://stackoverflow.com/questions/13023548/mysql-server-version-for-the-right-syntax-to-use-near-option-sql-select-limit-1