springboot 2.x 集成quartz持久化到一個單獨的dataSource時遇到的坑


由於希望可以在集群環境中運行定時job,但考慮到多個job實例有可能帶來job重復執行的問題,新項目的job打算從原生的spring task實現改成quartz job實現,並采用jdbc的存儲方式。

如果是把quartz的表初始化到原先springboot配置的同一個數據庫,並沒有太多問題,但考慮到這樣做會在業務表中插入很多不相關的表,決定把quartz的表建在單獨的一個庫中。查了quartz和springboot文檔,quartz中的配置

org.quartz.jobStore.dataSource=NAME

org.quartz.dataSource.NAME.driver
org.quartz.dataSource.NAME.URL
org.quartz.dataSource.NAME.user
org.quartz.dataSource.NAME.password
org.quartz.dataSource.NAME.maxConnections
org.quartz.dataSource.NAME.validationQuery
org.quartz.dataSource.NAME.validateOnCheckout
org.quartz.dataSource.NAME.discardIdleConnectionsSeconds

但集成到springboot中,在application.yml用了自己的配置

By default, an in-memory JobStore is used. However, it is possible to configure a JDBC-based store if a DataSource bean is available in your application and if the spring.quartz.job-store-type property is configured accordingly, as shown in the following example:

spring.quartz.job-store-type=jdbc
When the JDBC store is used, the schema can be initialized on startup, as shown in the following example:

spring.quartz.jdbc.initialize-schema=always

Advanced Quartz configuration properties can be customized using spring.quartz.properties.*.

查了些資料后,application.yml配置如下

spring:
    redis:
        host: localhost
        database: 2
        password: guanlouyi
        port: 6399
    datasource:
        url: jdbc:mysql://192.168.40.241:3306/fintech_public?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
        username: root
        password: 20.112@,l        
        driver-class-name: com.mysql.jdbc.Driver   
    quartz:
        job-store-type: jdbc
        jdbc:
            initialize-schema: always
        properties:
            org:
                quartz:
                    dataSource:
                        quartzDS: 
                            driver: com.mysql.jdbc.Driver
                            URL: jdbc:mysql://192.168.40.241:3306/fintech_quartz?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
                            user: root
                            password: 20.112@,l
                    scheduler:
                        instanceName: clusteredScheduler
                        instanceId: AUTO
                    jobStore:
                        class: org.quartz.impl.jdbcjobstore.JobStoreTX
                        driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
                        dataSource: quartzDS
                        tablePrefix: QRTZ_
                        isClustered: true
                        clusterCheckinInterval: 10000
                        useProperties: false  
                    threadPool:
                        class: org.quartz.simpl.SimpleThreadPool
                        threadCount: 10
                        threadPriority: 5
                        threadsInheritContextClassLoaderOfInitializingThread: true   

但是這樣配置的datasouce並不生效,用的還是原來的數據庫。查了些網上的資料,要給scheduler單獨的dataSource,而且發現springboot文檔里有

To have Quartz use a DataSource other than the application’s main DataSource, declare a DataSource bean, annotating its @Bean method with @QuartzDataSource. Doing so ensures that the Quartz-specific DataSource is used by both the SchedulerFactoryBean and for schema initialization.

於是application.yml改成(spring.datasource去掉改成@Bean@Primary形式,不這樣會報同時存在兩個dataSrouce,然后把quartz.dataSource的配置去掉了,加@QuartzDataSource注入:自以為)

spring:
    redis:
        host: localhost
        database: 2
        password: guanlouyi
        port: 6399
    quartz:
        job-store-type: jdbc
        jdbc:
            initialize-schema: never
        properties:
            org:
                quartz:
                    dataSource:
                    scheduler:
                        instanceName: clusteredScheduler
                        instanceId: AUTO
                    jobStore:
                        class: org.quartz.impl.jdbcjobstore.JobStoreTX
                        driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
                        tablePrefix: QRTZ_
                        isClustered: false
                        clusterCheckinInterval: 10000
                        useProperties: true
                    threadPool:
                        class: org.quartz.simpl.SimpleThreadPool
                        threadCount: 10
                        threadPriority: 5
                        threadsInheritContextClassLoaderOfInitializingThread: true

datasource: primary: url: jdbc:mysql://192.168.40.241:3306/fintech_public?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
        username: root
        password: 20.112@,l
        driver-class-name: com.mysql.jdbc.Driver   
    scheduler:
        url: jdbc:mysql://192.168.40.241:3306/fintech_quartz
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver

 代碼加上DataSourceConfig

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "datasource.primary")
    public DataSourceProperties primaryDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @ConfigurationProperties(prefix = "datasource.scheduler")
    public DataSourceProperties quartzDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean(name = "primaryDataSource")
    public DataSource primaryDataSource() {
        return primaryDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
    }

    @Bean(name = "quartzDataSource")
    @ConfigurationProperties(prefix = "datasource.scheduler")
    @QuartzDataSource public DataSource quartzDataSource() {
        DataSource datasource = quartzDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class)
                .build();
        return datasource;
    }

啟動報錯:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'adminEventsMapper' defined in file [E:\git\fintech-parent\fintech-microservice-dao\target\classes\com\panshi\fintech\microservice\dao\mapper\AdminEventsMapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required

 

分析:可能是把spring.datasource去掉,用@Bean和@Primary的形式生成的DataSource順序發生了改變,導致sqlSessionFactory和sqlSessionTemplate沒有生成,mybatis的Mapper初始化時沒有找到,在Mapper注入的地方加上@Lazy可以解決,但不打算采用此方法。后來網上看到有人也自己初始化sqlSessionFactory和sqlSessionTemplate,於是加上:

    /**
     * 創建 SqlSessionFactory
     */
    @Bean(name = "sqlSessionFactory")
    @Primary
    public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        // bean.setMapperLocations(new
        // PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/db1/*.xml"));
        return bean.getObject();
    }


    @Bean(name = "sqlSessionTemplate")
    @Primary
    public SqlSessionTemplate primarySqlSessionTemplate(
            @Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

這個問題解決,但又出現另一個問題:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'quartzScheduler' defined in class path resource [org/springframework/boot/autoconfigure/quartz/QuartzAutoConfiguration.class]: Invocation of init method failed; nested exception is org.quartz.SchedulerConfigException: DataSource name not set.

后來折騰了老半天,還是把dataSource加回application.yml

eureka:
    client:
        serviceUrl:
            defaultZone: http://localhost:8762/eureka
logging:
    path: /opt
    level:
        ROOT: DEBUG
        com.panshi.fintech: DEBUG
spring:
    redis:
        host: localhost
        database: 2
        password: guanlouyi
        port: 6399
    quartz:
        job-store-type: jdbc
        jdbc:
            initialize-schema: always
        properties:
            org:
                quartz:
 dataSource: quartzDataSource: driver: com.mysql.jdbc.Driver URL: jdbc:mysql://192.168.40.241:3306/fintech_quartz
                            user: root
                            password: 20.112@,l  
                    scheduler:
                        instanceName: clusteredScheduler
                        instanceId: AUTO
                    jobStore:
                        class: org.quartz.impl.jdbcjobstore.JobStoreTX
                        driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
                        tablePrefix: QRTZ_
                        isClustered: false dataSource: quartzDataSource                         clusterCheckinInterval: 10000
                        useProperties: true
                    threadPool:
                        class: org.quartz.simpl.SimpleThreadPool
                        threadCount: 10
                        threadPriority: 5
                        threadsInheritContextClassLoaderOfInitializingThread: true
datasource:
    primary:
        url: jdbc:mysql://192.168.40.241:3306/fintech_public?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
        username: root
        password: 20.112@,l
        driver-class-name: com.mysql.jdbc.Driver   
    scheduler:
        url: jdbc:mysql://192.168.40.241:3306/fintech_quartz
        username: root
        password: 20.112@,l
        driver-class-name: com.mysql.jdbc.Driver
file:
    path: /opt
    access-path: http://localhost    
swagger:
    enabled: true

原來這個配置還是需要的,但同時還要@Bean生成schedule的dataSource,同時加上

@QuartzDataSource

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM