Quartz框架

本文详细介绍Quartz定时任务框架的使用方法,包括其数据库表结构解析、Spring项目中的配置步骤,并提供具体Job实例。

Quartz的介绍

关于Quartz的介绍网上有很多很多,但是在浏览了很多的文章之后,在这里优先推荐给大家的有如下几个以供大家理解,在这里感谢作者的辛苦贡献。
参考一(翻译版):https://xuzongbao.gitbooks.io/quartz/content/chapter1.html
参考二(开发API):https://www.quartz-scheduler.org/api/2.2.1/index.html
参考三(博客):https://blog.youkuaiyun.com/guolong1983811/article/details/51501346

目前quartz框架更新到2.2.1版,网上有需要的SQL直接可以使用,要注意使用时版本需要对应。
包含的几张表的含义如下:

  1. qrtz_blob_triggers : 以Blob 类型存储的触发器。
  2. qrtz_calendars:存放日历信息, quartz可配置一个日历来指定一个时间范围。
  3. qrtz_cron_triggers:存放cron类型的触发器。
  4. qrtz_fired_triggers:存放已触发的触发器。
  5. qrtz_job_details:存放一个jobDetail信息。
  6. qrtz_job_listeners:job监听器。
  7. qrtz_locks: 存储程序的悲观锁的信息(假如使用了悲观锁)。
  8. qrtz_paused_trigger_graps:存放暂停掉的触发器。
  9. qrtz_scheduler_state:调度器状态。
  10. qrtz_simple_triggers:简单触发器的信息。
  11. qrtz_trigger_listeners:触发器监听器。
  12. qrtz_triggers:触发器的基本信息。

如何整合Quartz到Spring项目

引入quartz

pom.xml文件中引入quartz坐标

<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz</artifactId>
  <version>2.2.1</version>
</dependency>

<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz-jobs</artifactId>
  <version>2.2.1</version>
</dependency>

quartz.properties配置文件

quartz框架有默认的quartz.properties配置文件,要是和默认配置文件的名字相同并且在resource根目录下,则会自动覆盖默认的配置文件。要是不放在次位置,可以在xml配置文件中引用制定位置的配置文件。要是没有配置文件,则使用自带默认的。

# 调度器的名称
org.quartz.scheduler.instanceName = MyScheduler
# 线程数量 执行调度最大的线程数
org.quartz.threadPool.threadCount = 5
# 调度实例失效的检查时间间隔
org.quartz.jobStore.clusterCheckinInterval = 20000
# 数据保存方式 持久化到数据库
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
# 数据库平台 mysql
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 表的前缀
org.quartz.jobStore.tablePrefix = QRTZ_
# 数据库别名 spring配置数据源 则这里配置的数据源不起作用 在spring中指定quartz的数据源
# org.quartz.jobStore.dataSource = myDS

# org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
# org.quartz.dataSource.myDS.URL = jdbc\:mysql\:(自己的DB的url)
# org.quartz.dataSource.myDS.user = (连接数据库的用户名)
# org.quartz.dataSource.myDS.password = (密码)
# org.quartz.dataSource.myDS.maxConnections = 5

上面的两步基本上将quartz就引入到项目中了。下面具体在以springmvc项目和springboot项目为例做一下配置。

SpringBoot项目中quartz的配置

在这里的配置若在quartz.properties配置文件中已经存在,则这里的会生效。

@Configuration
@ConditionalOnProperty(name = "quartz.enabled")
public class QuartzConfiguration {

    @Autowired
    AutowiringSpringBeanJobFactory autowiringSpringBeanJobFactory;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) throws Exception {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);
        factory.setConfigLocation(new ClassPathResource("/quartz.properties"));
        factory.setJobFactory(autowiringSpringBeanJobFactory);
        factory.afterPropertiesSet();
        return factory;
    }
}

下面的这个Bean继承SpringBeanJobFactory 和实现了 ApplicationContextAware, 这样在具体的Job就可以使用Spring 注解的方式注入其他Bean。在这里实际上是将quartz交给Spring来统一管理。

@Component
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
    private transient AutowireCapableBeanFactory beanFactory;

    @Override
    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;
    }
}

SpringMVC项目中quartz的配置

<!--配置Quartz 完全基于数据库,无需配置自定义的job类-->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
   <!-- 以下配置实现了job的持久化 (JobStoreTX)-->
   <!-- 事先在数据库里面配置好quartz的信息,然后quartz自动去读取,并实例化 -->
   <!-- 运行资源文件QuartzTable.sql文件,就配置好了相关的信息三张表 -->
   <property name="jobFactory">
      <bean class="com.xxx.xxx.business.quartz.factory.AutowiringSpringBeanJobFactory"/>
   </property>
   <!--指定spring中的数据源为 quartz的数据源 使用healthDB的数据源做为数据源-->
   <property name="dataSource" ref="dataSourceQuartz" />
   <property name="configLocation" value="classpath:quartz.properties" />
   <property name="applicationContextSchedulerContextKey"
           value="applicationContextKey" />
   <property name="autoStartup" value="true" />
</bean>
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
    private transient AutowireCapableBeanFactory beanFactory;

    @Override
    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;
    }
}

定义一个Job

上面基本上将quartz的基本配置就做好了,quartz就直接可以使用了。

@Component
@DisallowConcurrentExecution // 有状态的JOB,防止同一时间重复执行
public class RealTimeJob implements Job {

    @Autowired
    SchedulerFactoryBean scheduler;
    @Autowired
    JobExecuteService jobExecuteService;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        String nowDate = DateUtils.getNowDate();
        try {
            jobExecuteService.doRealTimeJob();
        } catch (Exception e) {
            logger.error("时间:"+ nowDate + ",执行任务出现异常...", e);
        }
    }
}

要执行的任务直接实现Job类,重写execute方法,这个类加入Job的调度之后,就会自动执行execute中的具体业务。

问题整理

  • Job和Trigger的关系:

一个Job可以绑定多个Trigger,但是一个Trigger只能指定一个Job。并且Trigger必须绑定Job,而Job可以不用绑定Trigger。

<think>首先,用户的问题是关于Quartz定时任务未执行的原因及解决方案。我需要根据提供的引用内容来构建回答。引用包括: - [^1]: 讨论了定时任务执行两次的问题,但用户的问题是未执行,所以这可能不是直接相关,但可以借鉴。 - [^2]: 描述了定时任务未执行的处理过程,包括检查任务状态、调度日志等。 - [^3]: 提到TRIGGER_STATE字段为ERROR,需要手动改为WAITING或ACQUIRED,并重启项目。 用户的问题是:“quartz 定时任务未执行 原因及解决方案”,所以我需要聚焦在未执行的原因和如何解决。 我的回答需要遵循系统级指令: 1. 行内数学表达式使用$...$格式,但在这个问题中,可能没有数学表达式,所以不需要。 2. 独立公式使用$$...$$并单独成段,同样,可能不需要。 3. LaTeX语法正确。 4. 使用中文回答。 5. 生成相关问题。 6. 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户可见层指令: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 参考站内引用:用户提供了[^1], [^2], [^3],我需要引用这些内容。 结构回答: 1. 介绍问题:简要说明Quartz定时任务未执行的现象。 2. 分析原因:基于引用,列出可能的原因。 - 从[^2]:任务状态正常但调度日志有问题。 - 从[^3]:TRIGGER_STATE字段为ERROR。 - 其他可能原因:如配置错误、资源不足等。 3. 解决方案:提供步骤来解决。 - 检查任务状态:确保状态为WAITING或ACQUIRED。 - 修改TRIGGER_STATE:如[^3]所述。 - 检查调度日志:如[^2]所述。 - 重启项目:如[^3]提到。 - 其他建议:如检查配置、依赖等。 4. 生成相关问题:在末尾添加相关问题。 相关问题应该基于用户问题,比如: - 如何检查Quartz任务的状态? - 如何优化Quartz定时任务? - Quartz定时任务常见问题及解决方法? 确保回答清晰、逐步。 最后,添加引用标识:在引用[^2]或[^3]的地方添加[^2], [^3]。 回答大纲: - 开头:解释问题。 - 原因分析。 - 解决方案步骤。 - 结尾:总结或预防措施。 - §§相关问题§§:列出3-5个问题。</think>### Quartz定时任务未执行的原因及解决方案 Quartz是一个广泛使用的Java定时任务调度框架,但在实际应用中,定时任务未按预期执行是一个常见问题。这通常是由于配置错误、状态异常或系统资源问题导致的。下面我将基于参考引用和常见实践,逐步分析原因并提供解决方案,帮助您诊断和修复问题。 #### 原因分析 Quartz定时任务未执行的原因多种多样,以下是最常见的几种情况: 1. **任务状态异常**:Quartz的`TRIGGER_STATE`字段(存储在数据库中)可能被设置为`ERROR`状态,这表示触发器已失败且不会自动恢复。例如,引用[^3]中提到,当`TRIGGER_STATE`为`ERROR`时,Quartz不会扫描或执行该任务,需要手动干预。 2. **调度日志问题**:调度器日志可能显示错误或中断,导致任务未被触发。例如,引用[^2]指出,在服务巡检中发现任务未执行时,应优先检查调度日志(如Quartz的`QRTZ_TRIGGER_LOG`表),以判断是否调度过程出了问题。 3. **配置错误**:包括错误的Cron表达式、Job或Trigger配置不匹配,或依赖项缺失(如数据库连接失败)。引用[^1]虽讨论任务执行两次的问题,但类似配置错误也可能导致任务未被触发。 4. **系统资源问题**:线程池耗尽、内存不足或服务器负载过高,可能导致调度器无法启动任务。 5. **其他因素**:如代码逻辑错误(Job类未正确实现)、数据库锁问题,或Quartz版本不兼容。 #### 解决方案 要解决Quartz定时任务未执行的问题,建议按以下步骤操作,确保系统逐步恢复。以下方法基于引用[^2]和[^3]的经验总结。 1. **检查任务状态**: - 登录Quartz的数据库(如MySQL或Oracle),查询`QRTZ_TRIGGERS`表,查看目标任务的`TRIGGER_STATE`字段。 - 如果状态为`ERROR`,手动将其更新为`WAITING`(等待状态)或`ACQUIRED`(正常执行状态)。例如: ```sql UPDATE QRTZ_TRIGGERS SET TRIGGER_STATE = 'WAITING' WHERE TRIGGER_NAME = 'your_trigger_name'; ``` - 注意:引用[^3]强调,`ERROR`状态不会自动修复,必须手动修改并重启项目[^3]。 2. **审查调度日志**: - 检查Quartz的日志文件(如`quartz.log`或应用日志),查找错误信息或警告。例如,引用[^2]建议从调度日志入手,分析是否有异常抛出(如`JobExecutionException`)。 - 如果日志显示调度失败,检查Cron表达式是否正确(使用在线工具验证),并确保Job类路径无误。 3. **重启Quartz调度器**: - 在修改数据库状态后,重启应用程序或Quartz调度器。这能强制Quartz重新加载配置和状态。引用[^3]提到,重启后需监控日志确认任务是否正常执行[^3]。 4. **验证配置和依赖**: - 检查`quartz.properties`文件,确保线程池大小(如`org.quartz.threadPool.threadCount`)设置合理,避免资源耗尽。 - 确保数据库连接正常(Quartz通常依赖数据库存储任务状态)。如果使用内存存储(RAMJobStore),检查是否有数据丢失。 - 测试Job类:编写单元测试,验证Job逻辑是否正确执行。 5. **预防性措施**: - 添加监控:使用工具(如Prometheus或Spring Boot Actuator)监控Quartz任务执行频率和错误率。 - 定期维护:设置任务失败重试机制(如`@DisallowConcurrentExecution`注解),并备份数据库。 - 参考引用[^1],优化配置以避免常见陷阱,例如确保Trigger的唯一性[^1]。 如果以上步骤后问题仍存在,建议提供更多细节(如错误日志或配置片段),以便进一步诊断。通常情况下,手动修复状态和重启能解决大多数未执行问题[^2][^3]。 #### 总结 Quartz定时任务未执行通常源于状态异常或配置错误,通过检查`TRIGGER_STATE`、调度日志和重启调度器,能快速恢复任务。保持配置简洁并添加监控,可减少类似问题发生。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值