type
status
date
Jul 26, 2024 04:04 AM
slug
summary
category
tags
password
icon
概述Quartz 集群引入Maven依赖DemoJobDemoJob01DemoJob02相关配置配置文件DataSourceConfiguration初始化 Quartz 表结构定时任务配置Bean 自动设置Scheduler 手动设置测试日志输入数据库的内容参考
概述
Quartz单机方案使用的存储器是Memory内存,而Quartz集群方案使用的存储器是 JDBC 存储器 JobStoreTX ,使用 MySQL 作为数据库。
两种方案的对比如下:
类型 | 优点 | 缺点 |
RAMJobStore | 不要外部数据库,配置容易,运行速度快 | 因为调度程序信息是存储在被分配给JVM的内存里面,所以,当应用程序停止运行时,所有调度信息将被丢失。另外因为存储到JVM内存里面,所以可以存储多少个Job和Trigger将会受到限制 |
JDBC作业存储 | 支持集群,因为所有的任务信息都会保存到数据库中,可以控制事物,还有就是如果应用服务器关闭或者重启,任务信息都不会丢失,并且可以恢复因服务器关闭或者重启而导致执行失败的任务 | 运行速度的快慢取决与连接数据库的快慢 |
Quartz集群基于数据库锁的同步,操作流程如下图所示:
Quartz 集群
引入Maven依赖
DemoJob
DemoJob01
- 相比DemoJob01来说,在类上添加了 Quartz 的
@DisallowConcurrentExecution
注解,保证相同 JobDetail 在多个 JVM 进程中,有且仅有一个节点在执行。
注意:
- 不是以 Quartz Job 为维度,保证在多个 JVM 进程中,有且仅有一个节点在执行,而是以
JobDetail
为维度。虽然说,绝大多数情况下,我们会保证一个 Job 和 JobDetail 是一一对应。所以,一定要搞清楚这个概念。实在有点懵逼,保证一个 Job 和 JobDetail 是一一对应就对了。
- 而 JobDetail 的唯一标识是 JobKey ,使用
name
+group
两个属性。一般情况下,我们只需要设置name
即可,而 Quartz 会默认group = DEFAULT
。
- 不过这里还有一点要补充,也是需要注意的,在 Quartz 中,相同 Scheduler 名字的节点,形成一个 Quartz 集群。在下文中,我们可以通过
spring.quartz.scheduler-name
配置项,设置 Scheduler 的名字。【重要】为什么要说这个呢?因为我们要完善一下上面的说法:通过在 Job 实现类上添加@DisallowConcurrentExecution
注解,实现在相同 Quartz Scheduler 集群中,相同 JobKey 的 JobDetail ,保证在多个 JVM 进程中,有且仅有一个节点在执行。
DemoJob02
相关配置
配置文件
- 配置项比较多,我们主要对比 「3.5 应用配置文件」 来看看。
- 在
spring.datasource
配置项下,用于创建多个数据源的配置。 user
配置,连接quartz-jdbc-user
库。目的是,为了模拟我们一般项目,使用到的业务数据库。quartz
配置,连接quartz-jdbc-quartz
库。目的是,Quartz 会使用单独的数据库。如果我们有多个项目需要使用到 Quartz 数据库的话,可以统一使用一个,但是要注意配置spring.quartz.scheduler-name
设置不同的 Scheduler 名字,形成不同的 Quartz 集群。
- 在
spring.quartz
配置项下: scheduler-name
配置,Scheduler 名字。job-store-type
配置,设置了使用"jdbc"
的 Job 存储器。properties.org.quartz.jobStore
配置,增加了 JobStore 相关配置。重点是,通过dataSource
配置项,设置了使用名字为"quartzDataSource"
的 DataSource 为数据源。在 DataSourceConfiguration 中,我们会使用spring.datasource.quartz
配置,来创建该数据源。jdbc
配置项,虽然名字叫这个,主要是为了设置使用 SQL 初始化 Quartz 表结构。这里,我们设置initialize-schema = never
,我们手动创建表结构。
DataSourceConfiguration
- 基于
spring.datasource.user
配置项,创建了名字为"userDataSource"
的 DataSource Bean 。并且,在其上我们添加了@Primay
注解,表示其是主数据源。
- 基于
spring.datasource.quartz
配置项,创建了名字为"quartzDataSource"
的 DataSource Bean 。并且,在其上我们添加了@QuartzDataSource
注解,表示其是 Quartz 的数据源。
初始化 Quartz 表结构
在 Quartz Download 地址,下载对应版本的发布包。解压后,我们可以在
src/org/quartz/impl/jdbcjobstore/
目录,看到各种数据库的 Quartz 表结构的初始化脚本。这里,因为我们使用 MySQL ,所以使用 tables_mysql_innodb.sql
脚本。在数据库中执行该脚本,完成初始化 Quartz 表结构。如下图所示:
关于每个 Quartz 表结构的说明,可以看看 Quartz 框架——JobStore 数据库表字段详解。
我们会发现,每个表都有一个
SCHED_NAME
字段,Quartz Scheduler 名字。这样,实现每个 Quartz 集群,数据层面的拆分。定时任务配置
完成上述的工作之后,我们需要配置 Quartz 的定时任务。目前,有两种方式:
- Bean 自动设置
- Scheduler 手动设置
Bean 自动设置
在 Quartz 调度器启动的时候,会根据该配置,自动调用如下方法:
Scheduler#addJob(JobDetail jobDetail, boolean replace)
方法,将 JobDetail 持久化到数据库。
Scheduler#scheduleJob(Trigger trigger)
方法,将 Trigger 持久化到数据库。
Scheduler 手动设置
- 在每个单元测试方法的最后,调用
Scheduler#scheduleJob(JobDetail jobDetail, Trigger trigger)
方法,将 JobDetail 和 Trigger 持久化到数据库。
- 如果想要覆盖数据库中的 Quartz 定时任务的配置,可以调用
Scheduler#scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace)
方法(也就是scheduler.scheduleJob(jobDetail, Sets.newSet(trigger), true);
),传入replace = true
进行覆盖配置。
测试
日志输入
启动Application,观察日志的输出
数据库的内容
quartz-jdbc-quartz
数据库中,表qrtz_job_details
的内容如下:quartz-jdbc-quartz
数据库中,表qrtz_cron_triggers
的内容如下:quartz-jdbc-quartz
数据库中,表qrtz_triggers
的内容如下:参考
- ‣
- 作者:Frank
- 链接:https://blog.franksteven.me//article/quartz_cluster
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。