>
post-detail

SpringBoot 3.5.3 给 Quartz 配置独立数据源

「技术」

3 分钟

11 阅读

0

2025-09-17

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 数据源

于是我找到了以下三个资料

第三个是在评论区里找到的信息。

总结出两点:

  1. quartz 数据源配置需要==添加 @QuartzDataSource 指定==
  2. 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)等调度数据持久化到关系型数据库的组件,但它们在设计目标、使用场景和事务管理方面存在关键区别。

以下是两者的主要区别:

  1. 核心来源与依赖
  • JobStoreTX:

    • 这是 Quartz 框架原生提供的 JDBC JobStore 实现。
    • 它不依赖于 Spring 框架,可以独立于 Spring 使用。
    • 直接由 Quartz 调度器(StdSchedulerFactory)配置和管理。
  • LocalDataSourceJobStore:

    • 这是 Spring 框架对 Quartz 的扩展实现,位于 spring-context-support 模块中。
    • 它是 JobStoreCMT 的一个子类,专门为在 Spring 管理的非-JTA (non-JTA) 本地事务环境中使用而设计。
    • 强依赖于 Spring 的 DataSource 和事务管理机制。

  1. 事务管理方式 (最关键的区别)

这是两者最核心的差异。

  • 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 一起使用。

  1. 数据源 (DataSource) 的使用
  • JobStoreTX:

    • 可以通过 Quartz 的配置文件 (quartz.properties) 直接配置 DataSource,或者通过代码注入。
    • 对 DataSource 的管理相对独立于应用的其他部分。
  • LocalDataSourceJobStore:

    • 必须使用由 Spring 容器管理的 DataSource Bean。
    • 通常通过 Spring 的配置(XML 或 Java Config)将同一个 DataSource 注入给 LocalDataSourceJobStore 和应用中的其他 DAO/Service 层,确保它们使用相同的连接池和事务上下文。

  1. 总结
特性JobStoreTXLocalDataSourceJobStore
来源Quartz 原生Spring 扩展
依赖 Spring否是
事务管理自行管理 (开启/提交/回滚)参与 Spring 管理的事务
适用环境Standalone, 非托管事务环境Spring 托管的本地事务环境
DataSource可独立配置必须使用 Spring Bean 的 DataSource
典型配置quartz.propertiesSpring 配置 (XML/Java)

简单来说:

  • 如果你 没有使用 Spring,或者你的应用是一个简单的独立应用,你应该使用 JobStoreTX。
  • 如果你 正在使用 Spring 框架,并且希望 Quartz 的数据库操作能 无缝集成到 Spring 的事务管理中(例如,一个 Service 方法同时更新业务数据和调度数据,需要保证两者在一个事务里),那么你应该使用 LocalDataSourceJobStore。

AI 可太好用了((

3. 总结

  1. 在 SpringBoot 3.5.3 中集成 Quartz。
  2. 在 SpringBoot 3.5.3 中配置多数据源。
  3. 在 SpringBoot 3.5.3 中给 Quartz 配置独立数据源,持久化数据。

0 人赞过

评论

评论加载中…