How to solve `dataSource or dataSourceClassName or jdbcUrl is required` when connecting to multiple datasources using Spring Boot
Problem
When accessing multiple datasources using Spring Boot’s JdbcTemplate
, you might encounter the following error:
Caused by: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required. at com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:1004) ~[HikariCP-3.4.5.jar:na]
This error occurs because HikariCP requires specific properties to be set for each datasource.
Environment
- Postgresql 10.15+
- MySQL 5.7+
- Spring Boot 2.3+
- JDK 1.8+
Debug
Debug #1: The build.gradle
of the app
The app is built using Gradle. Here is the relevant part of the build.gradle
file:
plugins { id 'org.springframework.boot' id 'io.spring.dependency-management' id 'java'}
group 'com.bswen.app4'version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories { mavenCentral()}
dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' runtimeOnly 'mysql:mysql-connector-java' runtimeOnly 'org.postgresql:postgresql' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' }}
test { useJUnitPlatform()}
Debug #2: The MultipleDBConfig
class
To connect to multiple datasources, a @Configuration
class is required:
package com.bswen.app4;
import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.boot.jdbc.DataSourceBuilder;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
@Configurationpublic class MultipleDBConfig { @Bean(name = "mysqlDb") @ConfigurationProperties(prefix = "spring.ds-mysql") public DataSource mysqlDataSource() { return DataSourceBuilder.create().build(); }
@Bean(name = "mysqlJdbcTemplate") public JdbcTemplate jdbcTemplate(@Qualifier("mysqlDb") DataSource dsMySQL) { return new JdbcTemplate(dsMySQL); }
@Bean(name = "postgresDb") @ConfigurationProperties(prefix = "spring.ds-postgresql") public DataSource postgresDataSource() { return DataSourceBuilder.create().build(); }
@Bean(name = "postgresJdbcTemplate") public JdbcTemplate postgresJdbcTemplate(@Qualifier("postgresDb") DataSource dsPostgres) { return new JdbcTemplate(dsPostgres); }}
Debug #3: The application.properties
file
The connection properties for the datasources are defined in application.properties
:
spring.ds-postgresql.url =jdbc:postgresql://47.1.2.7:5432/bswendbspring.ds-postgresql.username =bswenspring.ds-postgresql.password =123456
spring.ds-mysql.url = jdbc:mysql://47.1.2.7:3306/bswen2spring.ds-mysql.username = bswenspring.ds-mysql.password = 123456
Debug #4: The JDBC client
The JDBC client queries data from the multiple datasources:
package com.bswen.app4;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.boot.CommandLineRunner;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Component;
@Componentpublic class MultipleDBJDBCRunner implements CommandLineRunner { private static final Logger log = LoggerFactory.getLogger(MultipleDBJDBCRunner.class); @Autowired @Qualifier("mysqlJdbcTemplate") JdbcTemplate mysqlJdbcTemplate; @Autowired @Qualifier("postgresJdbcTemplate") JdbcTemplate postgresJdbcTemplate;
@Override public void run(String... args) throws Exception { log.info("Querying for users from mysql:"); mysqlJdbcTemplate.query( "SELECT id, name, emailid, phoneno,location FROM usermaster", new Object[] { }, (rs, rowNum) -> new UserMaster( rs.getInt("id"), rs.getString("name"), rs.getString("emailid"), rs.getString("phoneno"), rs.getString("location")) ).forEach(customer -> log.info(customer.toString()));
log.info("Querying for users from postgresql:"); postgresJdbcTemplate.query( "SELECT id, name, emailid, phoneno,location FROM usermaster", new Object[] { }, (rs, rowNum) -> new UserMaster( rs.getInt("id"), rs.getString("name"), rs.getString("emailid"), rs.getString("phoneno"), rs.getString("location")) ).forEach(customer -> log.info(customer.toString())); }}
Reason
According to the Spring Boot documentation, when using HikariCP
, the jdbc-url
property must be used instead of url
.
Solution
Edit your application.properties
to use jdbc-url
:
spring.ds-postgresql.jdbc-url =jdbc:postgresql://47.1.2.7:5432/bswendbspring.ds-postgresql.username =bswenspring.ds-postgresql.password =123456
spring.ds-mysql.jdbc-url = jdbc:mysql://47.1.2.7:3306/bswen2spring.ds-mysql.username = bswenspring.ds-mysql.password = 123456
After making this change, re-run the Spring Boot application. The error should be resolved, and the application should connect to both datasources successfully.
All the code is available on GitHub. You can download the example code here.
Final Words + More Resources
My intention with this article was to help others who might be considering solving such a problem. So I hope that’s been the case here. If you still have any questions, don’t hesitate to ask me by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!