Search code examples
javaspring-boothikaricp

HikariCP - Multiple datasources, only primary datasource's pool started (spring boot)


So, I've configured my spring boot application to handle multiple datasource everything is good, but I noticed that when I launch the application, the primary datasource's pool is started but not the others, only when they are needed (which sometimes results in nullpointer...)

2020-03-05 15:34:02.478  INFO 11172 --- [           main] be.MyApp.ESPI.EspiApplication           : 

Starting EspiApplication on BESVC-HQ2000928 with PID 11172 (C:\Users\...\Documents\MyApp\Others\ESPI\ESPI\target\classes started by ... in C:\Users\...\Documents\MyApp\Others\ESPI\ESPI)
2020-03-05 15:34:02.483  INFO 11172 --- [           main] be.MyApp.ESPI.EspiApplication           : The following profiles are active: dev
2020-03-05 15:34:03.149  INFO 11172 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2020-03-05 15:34:03.233  INFO 11172 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 65ms. Found 2 JPA repository interfaces.
2020-03-05 15:34:03.811  INFO 11172 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-03-05 15:34:04.433  INFO 11172 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-03-05 15:34:04.444  INFO 11172 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-03-05 15:34:04.444  INFO 11172 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.30]
2020-03-05 15:34:04.603  INFO 11172 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-03-05 15:34:04.603  INFO 11172 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2047 ms
2020-03-05 15:34:04.761  WARN 11172 --- [           main] com.zaxxer.hikari.HikariConfig           : FirstPool - maxLifetime is less than 30000ms, setting to default 1800000ms.
2020-03-05 15:34:04.761  INFO 11172 --- [           main] com.zaxxer.hikari.HikariDataSource       : FirstPool - Starting...
2020-03-05 15:34:05.095  INFO 11172 --- [           main] com.zaxxer.hikari.pool.PoolBase          : FirstPool - Driver does not support get/set network timeout for connections. (oracle.jdbc.driver.T4CConnection.getNetworkTimeout()I)
2020-03-05 15:34:05.099  INFO 11172 --- [           main] com.zaxxer.hikari.HikariDataSource       : FirstPool - Start completed.
2020-03-05 15:34:05.159  INFO 11172 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2020-03-05 15:34:05.243  INFO 11172 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.4.10.Final}
2020-03-05 15:34:05.414  INFO 11172 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
2020-03-05 15:34:05.554  INFO 11172 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.Oracle12cDialect
2020-03-05 15:34:06.519  INFO 11172 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-03-05 15:34:06.526  INFO 11172 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-03-05 15:34:06.853  WARN 11172 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2020-03-05 15:34:06.947  INFO 11172 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-03-05 15:34:07.115  INFO 11172 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-03-05 15:34:07.116  INFO 11172 --- [           main] be.myapp.ESPI.EspiApplication           : Started EspiApplication in 5.135 seconds (JVM running for 5.744)
2020-03-05 15:34:17.044  INFO 11172 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-03-05 15:34:17.044  INFO 11172 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2020-03-05 15:34:17.052  INFO 11172 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 8 ms
2020-03-05 15:34:17.087  WARN 11172 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariConfig           : SecondPool- maxLifetime is less than 30000ms, setting to default 1800000ms.
2020-03-05 15:34:17.087  INFO 11172 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource       : SecondPool- Starting...
2020-03-05 15:34:17.176  INFO 11172 --- [nio-8080-exec-1] com.zaxxer.hikari.pool.PoolBase          : SecondPool- Driver does not support get/set network timeout for connections. (oracle.jdbc.driver.T4CConnection.getNetworkTimeout()I)
2020-03-05 15:34:17.178  INFO 11172 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource       : SecondPool- Start completed.

As you can see FirstPool is started. Spring Application starts. Then, only when needed, the SecondPool is started... I wonder how I can force the pool to start before the application starts ?

EDIT : My properties file are like this :

# DataSource definitions :

first.datasource.jdbc-url=jdbc:oracle:thin:@*a host*
first.datasource.username=user1
first.datasource.password=xxxxxxxxx
first.datasource.poolName=FirstPool
first.datasource.maximumPoolSize=100
first.datasource.maxLifetime=10000

second.datasource.jdbc-url=jdbc:oracle:thin:@*another host*
second.datasource.username=user2
second.datasource.password=xxxxxxxxx
second.datasource.poolName=SecondPool
second.datasource.maximumPoolSize=100
second.datasource.maxLifetime=10000

Second part :

# Profile definition
[email protected]@

# JPA definitions
spring.jpa.show-sql=true
spring.jpa.database=oracle

# DataSource
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.dataSourceClassName=oracle.jdbc.pool.OracleDataSource
spring.datasource.hikari.dataSourceProperties.implicitCachingEnabled=true
spring.datasource.hikari.dataSourceProperties.fastConnectionFailoverEnabled=true

# Oracle specifics
oracle.net.tns_admin=${ORACLE_HOME}/NETWORK/ADMIN

The configuration class that handle the DB Configuration :

@Configuration
@PropertySource({ "classpath:application.properties", "classpath:application-${spring.profiles.active}.properties"})
@Primary
public class DBConfiguration {

    @Bean(name = "FirstDataSource")
    @ConfigurationProperties("first.datasource")
    @Primary
    public HikariDataSource FirstDataSource() {
        return (HikariDataSource) DataSourceBuilder.create().build();
    }

    @Bean(name = "SecondDataSource")
    @ConfigurationProperties("second.datasource")
    public HikariDataSource SecondDataSource() {
        return (HikariDataSource) DataSourceBuilder.create().build();
    }

    @Bean(name="FirstTM")
    @Autowired
    @Primary
    DataSourceTransactionManager FirstTM(@Qualifier ("FirstDataSource") DataSource datasource) {
        DataSourceTransactionManager txm  = new DataSourceTransactionManager(datasource);
        return txm;
    }

    @Bean(name="SecondTM")
    @Autowired
    DataSourceTransactionManager SecondTM(@Qualifier("SecondDataSource") DataSource datasource) {
        DataSourceTransactionManager txm  = new DataSourceTransactionManager(datasource);
        return txm;
    }


}

Solution

  • I've found the answer.

    So, first, the dataSources are all created, BUT, the pool attached to it are not created until asked. So the idea is to force their initialization when starting the application.

    This can be achieved like this (see How to configure hikari pool for eager initialization? ):

    You can use an ApplicationLoader and get a connection at startup:

    @Component
    public class HikariLoader implements ApplicationRunner {
    
      private final HikariDataSource hikariDataSource;
    
      @Autowired
      public HikariLoader(HikariDataSource hikariDataSource) {
        this.hikariDataSource = hikariDataSource;
      }
    
      @Autowired
      public void run(ApplicationArguments args) throws SQLException {
        hikariDataSource.getConnection();
      }
    }