
SpringBoot 3.5.3 给 Quartz 配置独立数据源
1 前言
我的博客网站需要统计浏览量,浏览量统计数据是在 Redis 中 ,并且目前采用的同步方式是定时任务定期将数据同步到 Mysql 中,所以就打算集成 Quartz 。
我查阅了资料后,我发现 Quartz 居然有持久化到数据库的功能,我就决定试试。
2 集成
2.1 配置 Quartz
先加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
在 application.yml 中添加配置:
spring:
quartz:
job-store-type: jdbc
jdbc:
initialize-schema: never // 手动导入,不自动创建表
scheduler-name: quartzScheduler
properties:
org:
quartz:
scheduler:
instanceName: xgrQuartzScheduler
instanceId: AUTO
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
dataSource: xgrDS
tablePrefix: QRTZ_
isClustered: true
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
dataSource:
xgrDS:
driver: com.mysql.cj.jdbc.Driver
URL: jdbc:mysql://xxx.xxx.xxx.xxx:3306/quartz_db?useSSL=false&serverTimezone=UTC
user: root
password: yourpassword
maxConnections: 10
然后在官网找到 MySQL 建表脚本 github-quartz-jdbcjobstore
找到 tables_mysql.sql 或者 tables_mysql_innodb.sql
注意一下官方原话:
PLEASE consider using mysql with innodb tables to avoid locking issues就是确保你的数据表是使用 innodb 引擎创建的。
打开 Navicat 创建表 quartz_db,导入 tables_mysql.sql
![[https://47.107.64.126/xgrblogbucket/image/20250917/5d55d677-b7cb-4d65-9e66-95d8c96ebd0a/Pasted image 20250913112955.png]]
启动项目。
不出意外的话,就要出意外了。 报错:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'quartzScheduler' defined in class path resource
[org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.class]: Could not initialize DataSource: xgrDS
查了下资料,原来这个 dataSource 是要自己配置一个呀。也就是 SpringBoot 中要配置多数据源,其中一个给 quartz 用。
那么下一步就先配置一下多数据源了。
2.2 SpringBoot 配置多数据源
参考文章: Spring Boot 2.7.5 HikariCP 连接池多数据源配置_springboot hikaricp 多数据源-CSDN博客
我的 SpringBoot 用的是 HikariDataSource 而不是 Druid,所以找了篇 HikariDataSource 配置多数据源的文章。
稍微改造一下 application.yml
spring:
datasource:
primary:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://localhost:3306/xgrblog?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2b8
username: # 自己的用户名
password: # 自己的密码
hikari:
connection-test-query: SELECT 1
connection-timeout: 60000
idle-timeout: 600000
max-lifetime: 600000
maximum-pool-size: 12
minimum-idle: 12
pool-name: XgrBlog2DB-HikariPool # 改一下连接池名字
quartz:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://localhost:3306/xgrblog-quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2b8
username: # 自己的用户名
password: # 自己的密码
hikari:
connection-test-query: SELECT 1
connection-timeout: 60000
idle-timeout: 600000
max-lifetime: 600000
maximum-pool-size: 12
minimum-idle: 12
pool-name: XgrBlog2DB-Quartz-HikariPool
然后创建一个配置类 HikariDataSourceConfig
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.quartz.QuartzDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class HikariDataSourceConfig {
@Primary
@Bean("primaryDataSourceProperties")
@ConfigurationProperties("spring.datasource.primary")
public DataSourceProperties primaryDataSourceProperties() {
return new DataSourceProperties();
}
@Primary
@Bean("primaryDataSource")
@Qualifier(value = "primaryDataSource")
@ConfigurationProperties("spring.datasource.primary.hikari")
public HikariDataSource primaryDataSource() {
return primaryDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean("quartzDataSourceProperties")
@ConfigurationProperties("spring.datasource.quartz")
public DataSourceProperties quartzDataSourceProperties() {
return new DataSourceProperties();
}
@Bean("quartzDataSource")
@QuartzDataSource
@Qualifier("quartzDataSource")
@ConfigurationProperties("spring.datasource.quartz.hikari")
public HikariDataSource quartzDataSource() {
return quartzDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
}
最后修改一下 application.yml 中 quartz 的配置
spring:
quartz:
job-store-type: jdbc
jdbc:
initialize-schema: never // 手动导入,不自动创建表
scheduler-name: quartzScheduler
properties:
org:
quartz:
scheduler:
instanceName: xgrQuartzScheduler
instanceId: AUTO
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
dataSource: quartzDataSource # 改成 Bean 名字
tablePrefix: QRTZ_
isClustered: true
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
# 删掉 dataSource 相关配置
启动 SpringBoot
不出意外的话,又要出意外了。
Caused by: org.quartz.JobPersistenceException: Failed to obtain DB connection from data source 'quartzDataSource': java.sql.SQLException: There is no DataSource named 'quartz'
Caused by: java.sql.SQLException: There is no DataSource named 'quartzDataSource'
怎么会找不到数据源呢?我翻了一下控制台: ![[https://xgrblog.cn/xgrblogbucket/image/20250917/6f646288-1ecd-4124-8d30-9c64567279e7/Pasted image 20250913114421.png]] 只启动了主数据源,没有启动 Quartz 数据源
于是我找到了以下三个资料
- SpringBoot - 集成Quartz框架之独立数据源(四)_springboot 配置quartz datasource-CSDN博客
- SpringBoot之独立quartz数据源 - 半纸情书 - 博客园
- Springboot2.6整合Quartz2.3.2找不到数据源问题记录_failed to obtain db connection from data source-CSDN博客
第三个是在评论区里找到的信息。
总结出两点:
- quartz 数据源配置需要==添加
@QuartzDataSource指定== application.yml中 quartz 的jobStore配置,需要将class: org.quartz.impl.jdbcjobstore.JobStoreTX改成 ==org.springframework.scheduling.quartz.LocalDataSourceJobStore==
修改以后,启动项目
不出意外的话……没出意外?!
![[https://xgrblog.cn/xgrblogbucket/image/20250917/3630fe4b-e197-469a-9387-dab70d512951/Pasted image 20250913115059.png]]
两个数据源启动成功
![[https://xgrblog.cn/xgrblogbucket/image/20250917/11996c35-d2f6-4d9a-b18d-e57f8d7ac7d2/Pasted image 20250913115133.png]]
定时任务执行成功
![[https://xgrblog.cn/xgrblogbucket/image/20250917/6da236e2-a67a-4a02-abf6-472065b9991b/Pasted image 20250913115504.png]]
数据库中也有数据
搞定。
为了搞明白为什么将 class: org.quartz.impl.jdbcjobstore.JobStoreTX 改成 org.springframework.scheduling.quartz.LocalDataSourceJobStore 就能成功,
我问了下 ai
org.quartz.impl.jdbcjobstore.JobStoreTX 和 org.springframework.scheduling.quartz.LocalDataSourceJobStore 都是 Quartz 调度框架用于将任务(jobs)、触发器(triggers)等调度数据持久化到关系型数据库的组件,但它们在设计目标、使用场景和事务管理方面存在关键区别。
以下是两者的主要区别:
- 核心来源与依赖
-
JobStoreTX:- 这是 Quartz 框架原生提供的 JDBC JobStore 实现。
- 它不依赖于 Spring 框架,可以独立于 Spring 使用。
- 直接由 Quartz 调度器(
StdSchedulerFactory)配置和管理。
-
LocalDataSourceJobStore:- 这是 Spring 框架对 Quartz 的扩展实现,位于
spring-context-support模块中。 - 它是
JobStoreCMT的一个子类,专门为在 Spring 管理的非-JTA (non-JTA) 本地事务环境中使用而设计。 - 强依赖于 Spring 的
DataSource和事务管理机制。
- 这是 Spring 框架对 Quartz 的扩展实现,位于
- 事务管理方式 (最关键的区别)
这是两者最核心的差异。
-
JobStoreTX:- 自行管理数据库连接和事务。
- 它会从配置的
DataSource获取连接,并自己调用connection.setAutoCommit(false)、commit()和rollback()来控制事务边界。 - 适用于 非托管环境(如 standalone Java 应用、简单的 Web 应用),即没有 JTA (Java Transaction API) 事务管理器的环境。
- 事务的开始、提交和回滚完全由 Quartz 内部逻辑处理。
-
LocalDataSourceJobStore:- 不直接管理事务,而是参与 Spring 管理的事务。
- 它假设数据库操作是在 Spring 的声明式或编程式事务管理之下进行的。
- 当 Spring 开启了一个事务时,
LocalDataSourceJobStore会获取 Spring 事务同步的Connection并参与该事务。它不会自己调用commit()或rollback(),而是让 Spring 的事务管理器来最终决定提交还是回滚。 - 适用于 Spring 托管的本地事务环境,通常与
DataSourceTransactionManager一起使用。
- 数据源 (
DataSource) 的使用
-
JobStoreTX:- 可以通过 Quartz 的配置文件 (
quartz.properties) 直接配置DataSource,或者通过代码注入。 - 对
DataSource的管理相对独立于应用的其他部分。
- 可以通过 Quartz 的配置文件 (
-
LocalDataSourceJobStore:- 必须使用由 Spring 容器管理的
DataSourceBean。 - 通常通过 Spring 的配置(XML 或 Java Config)将同一个
DataSource注入给LocalDataSourceJobStore和应用中的其他 DAO/Service 层,确保它们使用相同的连接池和事务上下文。
- 必须使用由 Spring 容器管理的
- 总结
| 特性 | JobStoreTX | LocalDataSourceJobStore |
|---|---|---|
| 来源 | Quartz 原生 | Spring 扩展 |
| 依赖 Spring | 否 | 是 |
| 事务管理 | 自行管理 (开启/提交/回滚) | 参与 Spring 管理的事务 |
| 适用环境 | Standalone, 非托管事务环境 | Spring 托管的本地事务环境 |
| DataSource | 可独立配置 | 必须使用 Spring Bean 的 DataSource |
| 典型配置 | quartz.properties | Spring 配置 (XML/Java) |
简单来说:
- 如果你 没有使用 Spring,或者你的应用是一个简单的独立应用,你应该使用
JobStoreTX。 - 如果你 正在使用 Spring 框架,并且希望 Quartz 的数据库操作能 无缝集成到 Spring 的事务管理中(例如,一个 Service 方法同时更新业务数据和调度数据,需要保证两者在一个事务里),那么你应该使用
LocalDataSourceJobStore。
AI 可太好用了((
3. 总结
- 在 SpringBoot 3.5.3 中集成 Quartz。
- 在 SpringBoot 3.5.3 中配置多数据源。
- 在 SpringBoot 3.5.3 中给 Quartz 配置独立数据源,持久化数据。
0 人赞过
评论
评论加载中…