spring整合quartz有两种方式:

一.常见是使用配置文件,将定时任务保存到内存中

简单示例:

<!-- 短信催还提醒任务调度 -->
<bean id="overdueRecall"
class="com.sursen.souba.ddlibserve.quartz.OverdueRecallTimerTask" /> <!--定义定时执行overdueRecallTimerTask 这个bean中的overdueRecall()方法-->
<bean id="overdueRecallTask"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="overdueRecall" />
</property>
<property name="targetMethod">
<value>overdueRecall</value>
</property>
</bean> <!--触发器的bean的设置,要触发的jobDetail是overdueRecallTask-->
<bean id="overdueRecallTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="overdueRecallTask" />
</property>
<property name="cronExpression">
<!-- 每天17:00运行 -->
<value>0 0 17 * * ?</value>
<!--<value>0 05 18 * * ?</value>-->
</property>
</bean> <!--管理触发器的总设置,管理我们的触发器列表,可以在bean的list中放置多个触发器。-->
<bean autowire="no"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="overdueRecallTrigger" />
</list>
</property>
</bean>

这中方式配置简单,但是存在问题。

1.定时任务信息都报错在内存中,服务器重启会丢失信息

2.每个定时任务都是一串配置,定时任务多了不好管理

3.任务时间修改后要重新发布项目

二.quartz持久化(quartz1.6,最新版本的quartz稍有变动)

研究了一下quartz的相关文档,quartz本身就提供将任务和触发器持久化到数据库中的功能

详见<Quartz-Job-Scheduling-Framework>一书

要实现很简单:

1.安装 Quartz 数据库表

Quartz 包括了所有被支持的数据库平台的 SQL 脚本。你能在 <quartz_home>/docs/dbTables 目录下找到那些 SQL 脚本,这里的 <quartz_home> 是解压Quartz 分发包后的目录。

2.配置 JobStoreTX

要告诉 Quartz 运行环境你想使用一个别的 JobStore 而不是默认的 RAMJobStore,你必须配置几个属性。配置它们的顺序无关紧要,只要保证在第一次运行程序之前都做了设置。

在你的classpath下加入一个配置文件quartz.properties参数如下:

表 6.3. 可用于设置 JobStoreTX 的配置属性

属性 默认值
org.quartz.jobStore.driverDelegateClass  
描述:能理解不同数据库系统中某一特定方言的驱动代理
org.quartz.jobStore.dataSource  
描述:用于 quartz.properties 中数据源的名称
org.quartz.jobStore.tablePrefix QRTZ_
描述:指定用于 Scheduler 的一套数据库表名的前缀。假如有不同的前缀,Scheduler 就能在同一数据库中使用不同的表。
org.quartz.jobStore.userProperties False
描述:"use properties" 标记指示着持久性 JobStore 所有在 JobDataMap 中的值都是字符串,因此能以 名-值 对的形式存储,而不用让更复杂的对象以序列化的形式存入 BLOB 列中。这样会更方便,因为让你避免了发生于序列化你的非字符串的类到 BLOB 时的有关类版本的问题。
org.quartz.jobStore.misfireThreshold 60000
描述:在 Trigger 被认为是错过触发之前,Scheduler 还容许 Trigger 通过它的下次触发时间的毫秒数(译者注:据原文翻译,真的不好理解,实际效果可参看:http://www.blogjava.net/Unmi/archive/2007/10/23/153413.html 我在评论中的实验)。默认值(假如你未在配置中存在这一属性条目) 是 60000(60 秒)。这个不仅限于JDBC-JobStore;它也可作为 RAMJobStore 的参数
org.quartz.jobStore.isClustered False
描述:设置为 true 打开集群特性。如果你有多个 Quartz 实例在用同一套数据库时,这个属性就必须设置为 true。
org.quartz.jobStore.clusterCheckinInterval 15000
描述:设置一个频度(毫秒),用于实例报告给集群中的其他实例。这会影响到侦测失败实例的敏捷度。它只用于设置了 isClustered 为 true 的时候。
org.quartz.jobStore.maxMisfiresToHandleAtATime 20
描述:这是 JobStore 能处理的错过触发的 Trigger 的最大数量。处理太多(超过两打) 很快会导致数据库表被锁定够长的时间,这样就妨碍了触发别的(还未错过触发) trigger 执行的性能。
org.quartz.jobStore.dontSetAutoCommitFalse False
描述:设置这个参数为 true 会告诉 Quartz 从数据源获取的连接后不要调用它的setAutoCommit(false) 方法。这在少些情况下是有帮助的,比如假如你有这样一个驱动,它会抱怨本来就是关闭的又来调用这个方法。这个属性默认值是 false,因为大多数的驱动都要求调用 setAutoCommit(false)。
org.quartz.jobStore.selectWithLockSQL SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE
描述:这必须是一个从 LOCKS 表查询一行并对这行记录加锁的 SQL 语句。假如未设置,默认值就是 SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE,这能在大部分数据库上工作。{0} 会在运行期间被前面你配置的TABLE_PREFIX 所替换。
org.quartz.jobStore.txIsolationLevelSerializable False
描述:值为 true 时告知 Quartz(当使用 JobStoreTX 或 CMT) 调用 JDBC 连接的setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE) 方法。这有助于阻止某些数据库在高负载和长时间事物时锁的超时。

示例,使用的是sqlserver数据库:

#org.quartz.scheduler.instanceName = Mscheduler
org.quartz.scheduler.instanceId = AUTO #============================================================================
# Configure ThreadPool
#============================================================================ orgorg.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 3
org.quartz.threadPool.threadPriority = 5 #============================================================================
# Configure JobStore
#============================================================================ #orgorg.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
orgorg.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
orgorg.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegate
org.quartz.jobStore.useProperties = true
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.isClustered = false
org.quartz.jobStore.maxMisfiresToHandleAtATime=1
#============================================================================
# Configure Datasources
#============================================================================ org.quartz.dataSource.myDS.driver = net.sourceforge.jtds.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc\:jtds\:sqlserver\://ip/dbk
org.quartz.dataSource.myDS.user = db2
org.quartz.dataSource.myDS.password = db2
org.quartz.dataSource.myDS.maxConnections = 5 #============================================================================
# Configure Plugins
#============================================================================ #orgorg.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin #orgorg.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
#org.quartz.plugin.jobInitializer.fileNames = jobs.xml
#org.quartz.plugin.jobInitializer.overWriteExistingJobs = true
#org.quartz.plugin.jobInitializer.failOnFileNotFound = true
#org.quartz.plugin.jobInitializer.scanInterval = 10
#org.quartz.plugin.jobInitializer.wrapInUserTransaction = false

然后可直接运行以下测试类:

package com.sursen.test.service;  

import java.text.ParseException;  

import org.apache.commons.lang.StringUtils;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory; public class QuartzTest {
private static SchedulerFactory sf = new StdSchedulerFactory();
private static String JOB_GROUP_NAME = "ddlib";
private static String TRIGGER_GROUP_NAME = "ddlibTrigger"; /**添加一个定时任务,使用默认的任务组名,触发器名,触发器组名*/
public static void addJob(String jobName,Job job,String cronExpression)
throws SchedulerException, ParseException{
addJob(jobName,null,jobName,null,job,cronExpression);
} /**
* 添加一个定时任务
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param job 任务
* @param cronExpression 时间设置,参考quartz说明文档
*/
public static void addJob(String jobName,String jobGroupName,
String triggerName,String triggerGroupName,Job job,String cronExpression)
throws SchedulerException, ParseException{
if(StringUtils.isBlank(jobGroupName)){
jobGroupName = JOB_GROUP_NAME;
}
if(StringUtils.isBlank(triggerGroupName)){
triggerGroupName = TRIGGER_GROUP_NAME;
}
Scheduler sched = sf.getScheduler();
JobDetail jobDetail = new JobDetail(jobName, jobGroupName, job.getClass());//任务名,任务组,任务执行类
CronTrigger trigger = new CronTrigger(jobName,triggerGroupName,cronExpression);//触发器名,触发器组,cron表达式
sched.scheduleJob(jobDetail,trigger);
//启动
if(!sched.isShutdown()){
sched.start();
}
} /**
* 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
*/
public static void modifyJobTime(String jobName,String cronExpression)
throws SchedulerException, ParseException{
modifyJobTime(jobName, null, cronExpression);
} /**
* 修改一个任务的触发时间
*/
public static void modifyJobTime(String triggerName,String triggerGroupName,
String cronExpression)throws SchedulerException, ParseException{
if(StringUtils.isBlank(triggerGroupName)){
triggerGroupName = TRIGGER_GROUP_NAME;
}
Scheduler sched = sf.getScheduler();
Trigger trigger = sched.getTrigger(triggerName,triggerGroupName);
if(trigger != null){
CronTrigger ct = (CronTrigger)trigger;
//修改时间
ct.setCronExpression(cronExpression);
//重启触发器
sched.resumeTrigger(triggerName,triggerGroupName);
}
} /**移除一个任务和触发器(使用默认的任务组名,触发器名,触发器组名)*/
public static void removeJob(String jobName,String triggerName)
throws SchedulerException{
removeJob(jobName, null, triggerName, null);
} /**移除一个任务和触发器 */
public static void removeJob(String jobName,String jobGroupName,
String triggerName,String triggerGroupName)
throws SchedulerException{
if(StringUtils.isBlank(jobGroupName)){
jobGroupName = JOB_GROUP_NAME;
}
if(StringUtils.isBlank(triggerGroupName)){
triggerGroupName = TRIGGER_GROUP_NAME;
}
Scheduler sched = sf.getScheduler();
sched.pauseTrigger(triggerName,triggerGroupName);//停止触发器
sched.unscheduleJob(triggerName,triggerGroupName);//移除触发器
sched.deleteJob(jobName,jobGroupName);//删除任务
} public static void main(String[] args) throws SchedulerException, ParseException {
// addJob("test", new TestJob(), "*/5 * * * * ?");
// addJob("zht", new TestJob(), "*/10 * * * * ?");
// removeJob("myJob","myJobGroup", "myTrigger","myTriggerGroup");
removeJob("test","test");
removeJob("zht","zht"); }
}

三.spring下quartz的持久化

在spring配置文件中加入以下代码

<!-- quartz持久化存储  -->
<bean id="scheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >
<!-- <property name="dataSource">
<ref bean="ddlibserveDataSource" />
</property> -->
<!-- <property name="schedulerName" value="Mscheduler" /> -->
<property name="configLocation" value="classpath:quartz.properties" />
<property name="applicationContextSchedulerContextKey"
value="applicationContextKey" />
<property name="autoStartup" value="true" />
</bean>

之后将

<bean id="scheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >

注入到所需要的service中即可.

其中

<!--   <property name="dataSource">
<ref bean="ddlibserveDataSource" />
</property> -->

为注入的数据源,

如果使用这种方式那配置文件中的相关配置要注释掉.

或者将配置文件中信息写入到spring配置文件中:

<!-- quartz持久化存储  -->
<bean id="scheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >
<property name="dataSource">
<ref bean="ddlibserveDataSource" />
</property> <!--方式一 : quartz.properties配置文件是放在classpath下
<property name="configLocation" value="classpath:quartz.properties" /> --> <!--方式二 : quartz.properties配置文件是放在WEB-INF下
<property name="configLocation" value="/WEB-INF/quartz.properties" /> --> <!--方式三 : quartz.properties配置文件写入到配置XML中 -->
<property name="quartzProperties">
<props>
<prop key="org.quartz.scheduler.instanceName">quartzScheduler</prop>
<prop key="org.quartz.scheduler.instanceId">AUTO</prop>
<prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
<prop key="org.quartz.threadPool.threadCount">3</prop>
<prop key="org.quartz.threadPool.threadPriority">5</prop>
<prop key="org.quartz.jobStore.misfireThreshold">60000</prop>
<prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
<prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.MSSQLDelegate </prop>
<prop key="org.quartz.jobStore.selectWithLockSQL">SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?</prop>
<prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
<prop key="org.quartz.jobStore.isClustered">true</prop>
<prop key="org.quartz.jobStore.clusterCheckinInterval">20000</prop>
</props>
</property>
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<property name="autoStartup" value="true" />
</bean>

期间遇到的问题留作记录:

1.持久化时遇到报字段不正确或表不存在的问题

原因: 我使用的是quartz 2.1建的表而jar包是1.6的

解决方法: 将建表语句和jar包统一版本即可

2.报dataSource name不存在的问题

原因: quartz.properties中的 org.quartz.jobStore.dataSource = myDS

忘记打开或者与数据源配置没有保持一致

解决方法: 打开保持一致即可

3.使用注入dataSource时报

Failure obtaining db row lock: 第 1 行: FOR UPDATE 子句仅允许用于 DECLARE CU...

改为数据源写在quartz.properties中解决

还不清楚为什么注入不行(解决)

org.quartz.jobStore.selectWithLockSQL SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE
描述:这必须是一个从 LOCKS 表查询一行并对这行记录加锁的 SQL 语句。假如未设置,默认值就是 SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE,这能在大部分数据库上工作。{0} 会在运行期间被前面你配置的TABLE_PREFIX 所替换。

这条sql在sqlserver2000中不能运行修改为:

org.quartz.jobStore.selectWithLockSQL=SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?   

问题解决

 <property name="configLocation" value="classpath:quartz.properties" />

这种方式配置quartz.properties文件需要放在classpath下,而我们项目中都是放在Web-info下

可直接修改为:

<property name="configLocation" value="/WEB-INF/quartz.properties" />  

4.在spring配置文件中

<bean id="quartzServiceImpl"
class="com.sursen.test.service.impl.QuartzServiceImpl">
<property name="scheduler">
<ref bean="scheduler" />
</property>
</bean>
以这种方式将scheduler即StdScheduler scheduler注入到相关service中报找不到该property的错误
而service中是肯定存在的 : private StdScheduler scheduler;
改为spring的注解形式注入
@Autowired
private StdScheduler scheduler;

也不行,再改为

@Resource
private StdScheduler scheduler;

或者

@Qualifier("scheduler")
private StdScheduler scheduler;

则没有问题,具体原因还在查找

本文转自:http://haiziwoainixx.iteye.com/blog/1838055

spring整合quartz并持久化的更多相关文章

  1. Spring整合Quartz实现持久化、动态设定时间

    一.spring整合 网上一搜有很多整合的方式,这里我采用了其中的一种(暂时还没有对其他的方法研究过). 对于spring的整合其中的任务,spring提供了几个类.接口(这些类都实现了Job接口): ...

  2. Spring整合Quartz定时任务 在集群、分布式系统中的应用(Mysql数据库环境)

    Spring整合Quartz定时任务 在集群.分布式系统中的应用(Mysql数据库环境)   转载:http://www.cnblogs.com/jiafuwei/p/6145280.html 单个Q ...

  3. 使用Spring整合Quartz轻松完成定时任务

    一.背景 上次我们介绍了如何使用Spring Task进行完成定时任务的编写,这次我们使用Spring整合Quartz的方式来再一次实现定时任务的开发,以下奉上开发步骤及注意事项等. 二.开发环境及必 ...

  4. Spring整合Quartz定时任务执行2次,Spring定时任务执行2次

    Spring整合Quartz定时任务执行2次,Spring定时任务执行2次 >>>>>>>>>>>>>>>&g ...

  5. spring整合quartz时间任务调度框架

    spring整合quartz框架 1.创建maven工程 2.导入jar包(pom.xml) <dependencies> <dependency> <groupId&g ...

  6. Spring quartz Job不能依赖注入,Spring整合quartz Job任务不能注入

    Spring quartz Job不能依赖注入,Spring整合quartz Job任务不能注入 Spring4整合quartz2.2.3中Job任务使用@Autowired不能注入 >> ...

  7. 使用spring整合Quartz实现—定时器

    使用spring整合Quartz实现—定时器(Maven项目做演示) 不基于特定的基类的方法 一,开发环境以及依赖的jar包 Spring 4.2.6.RELEASE Maven 3.3.9 Jdk ...

  8. Spring整合Quartz分布式调度

    前言 为了保证应用的高可用和高并发性,一般都会部署多个节点:对于定时任务,如果每个节点都执行自己的定时任务,一方面耗费了系统资源,另一方面有些任务多次执行,可能引发应用逻辑问题,所以需要一个分布式的调 ...

  9. Spring整合Quartz分布式调度(山东数漫江湖)

    前言 为了保证应用的高可用和高并发性,一般都会部署多个节点:对于定时任务,如果每个节点都执行自己的定时任务,一方面耗费了系统资源,另一方面有些任务多次执行,可能引发应用逻辑问题,所以需要一个分布式的调 ...

随机推荐

  1. 《ASP.NET MVC4 WEB编程》学习笔记------ViewBag、ViewData和TempData的使用和区别

    本文转自大卫Baby ViewBag和ViewData其实是互通的ViewBag和ViewData的区别:ViewBag 不再是字典的键值对结构,而是 dynamic 动态类型,它会在程序运行的时候动 ...

  2. Rehashing

    The size of the hash table is not determinate at the very beginning. If the total size of keys is to ...

  3. spring3.2.8+quartz2.2.0(比较全,对比quartz1.x的配置)

    spring3.2.8 + quartz2.2.0报错: java.lang.IncompatibleClassChangeError: class org.springframework.sched ...

  4. Ubuntu安装steam游戏平台的解决方案

    steam是一个游戏平台,上面提供了很多收费和免费的游戏,在安装的过程中遇到了一些问题,所以把自己遇到的问题及解决方案分享出来供大家参考. 第一步:安装steam平台 sudo apt-get ins ...

  5. 优秀前端工程师应该掌握的内容(转自:github)

    程序 标准规范 ECMAScript HTTP 知识储备 作用域/闭包 数据结构 算法 编程范式 函数式 面向对象 基于原型 面向方面 设计模式 软件架构 MVC MVVM 安全 XSS CSRF 富 ...

  6. Tomcat 解决The code of method _jspService(HttpServletRequest, HttpServletResponse) is exceeding the 65535 bytes limit

    解法: 修改tomcat下的web.xml,     搜索:JspServlet, 增加: <init-param> <param-name>mappedfile</pa ...

  7. Android实现圆形圆角图片

    本文主要使用两种方法实现图形圆角图片 自定View加上使用Xfermode实现 Shader实现 自定View加上使用Xfermode实现 /** * 根据原图和变长绘制圆形图片 * * @param ...

  8. 微博feed系统的推(push)模式和拉(pull)模式和时间分区拉模式架构探讨

    sns系统,微博系统都应用到了feed(每条微博或者sns里的新鲜事等我们称作feed)系统,不管是twitter.com或者国内的新浪微博,人人网等,在各种技术社区,技术大会上都在分享自己的feed ...

  9. 让Entity Framework支持MySql数据库(转载)

    转载地址:http://www.cnblogs.com/wintersun/archive/2010/12/12/1903861.html Entity Framework 4.0 也可以支持大名鼎鼎 ...

  10. hdu 1757 矩阵快速幂 **

    一看正确率这么高,以为是水题可以爽一发,结果是没怎么用过的矩阵快速幂,233 题解链接:点我 #include<iostream> #include<cstring> ; us ...