How to setup datasources dynamically in springboot
Introduction
This post demonstrates how to dynamically configure multiple data sources in a Spring Boot application. We will explore three different approaches to set up data sources, including using application.properties and DataSourceBuilder.
Environments
- SpringBoot 1.5.12+
- Java 1.8
The Pom.xml
Here is the Spring Boot version and dependencies used in this example:
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.12.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope></dependency>Three Ways to Setup DataSources
There are three primary methods to configure data sources in a Spring application:
- The Default Way: Configure via
application.properties. Spring Boot automatically sets up the data source based on the provided properties. - Dynamic Way 1: Use
DataSourceBuilderalong withapplication.propertiesin a@Configurationbean. - Dynamic Way 2: Use
DataSourceBuilderwithout any properties file, defining all configurations programmatically.
Here is a visual summary:

The Database and Table
For demonstration purposes, a local database is set up as follows:
CREATE DATABASE `test` CHARACTER SET utf8 COLLATE utf8_bin;A table tbl_student is created in the database:
CREATE TABLE `tbl_student` ( `ID` int(10) NOT NULL AUTO_INCREMENT, `NAME` varchar(100) NOT NULL, `BRANCH` varchar(255) NOT NULL, `PERCENTAGE` int(3) NOT NULL, `PHONE` int(10) NOT NULL, `EMAIL` varchar(255) NOT NULL, PRIMARY KEY (`ID`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;A sample record is inserted into the table:
INSERT INTO `tbl_student` (`ID`, `NAME`, `BRANCH`, `PERCENTAGE`, `PHONE`, `EMAIL`)VALUESThe Domain Class Student
public class Student { private int id; private String name; private String branch; private int percentage; private int phone; private String email;
// Getters and setters ...}The Default Way: Setup via application.properties
The application.properties
Configure the database properties in application.properties:
spring.datasource.username=rootspring.datasource.password=123456spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8spring.datasource.driver=com.mysql.jdbc.DriverThe DAO Class
@Componentpublic class StudentDao { @Autowired private JdbcTemplate jdbcTemplateObject;
public Student getStudent(Integer id) { String SQL = "select * from tbl_student where id = ?"; Student student = jdbcTemplateObject.queryForObject(SQL, new Object[]{id}, new StudentMapper());
return student; }
class StudentMapper implements RowMapper<Student> { public Student mapRow(ResultSet rs, int rowNum) throws SQLException { Student student = new Student(); student.setId(rs.getInt("id")); student.setName(rs.getString("name"));
return student; } }}The JUnit Test Case
@RunWith(SpringRunner.class)@SpringBootTestpublic class TestDefaultDataSource { @Autowired private StudentDao studentDao; @Test public void testSimpleSelect() { Student student = studentDao.getStudent(1); assertNotNull(student); assertEquals(student.getName(),"jack"); }}Running the test case results in a green bar:

The Dynamic Way 1: Setup via DataSourceBuilder and application.properties
The application.properties
Configure the second data source in application.properties:
spring.datasource2.username=rootspring.datasource2.password=123456spring.datasource2.url=jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8spring.datasource2.driver=com.mysql.jdbc.DriverThe Config Bean for the DataSource
@Configurationpublic class DataSourceConfig { @Bean(name = "dsMaster") @Primary @ConfigurationProperties(prefix="spring.datasource2") public DataSource masterDataSource() { return DataSourceBuilder.create().build(); }
@Bean(name = "jdbcMaster") @Autowired public JdbcTemplate masterJdbcTemplate(@Qualifier("dsMaster") DataSource dsMaster) { return new JdbcTemplate(dsMaster); }}The DAO Class
@Componentpublic class StudentDao { @Autowired @Qualifier("jdbcMaster") private JdbcTemplate jdbcTemplateObject;
public Student getStudent(Integer id) { String SQL = "select * from tbl_student where id = ?"; Student student = jdbcTemplateObject.queryForObject(SQL, new Object[]{id}, new StudentMapper());
return student; }
class StudentMapper implements RowMapper<Student> { public Student mapRow(ResultSet rs, int rowNum) throws SQLException { Student student = new Student(); student.setId(rs.getInt("id")); student.setName(rs.getString("name"));
return student; } }}The JUnit Test Case
@RunWith(SpringRunner.class)@SpringBootTestpublic class TestDefaultDataSource { @Autowired private StudentDao studentDao; @Test public void testSimpleSelect() { Student student = studentDao.getStudent(1); assertNotNull(student); assertEquals(student.getName(),"jack"); }}Running the test case results in a green bar:

The Dynamic Way 2: Setup Only by DataSourceBuilder
The Config Bean for the DataSource
@Configurationpublic class DataSourceConfig { @Bean(name="dsCustom") public DataSource dataSource() { return DataSourceBuilder .create() .username("root") .password("123456") .url("jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8") .driverClassName("com.mysql.jdbc.Driver") .build(); }
@Bean(name = "jdbcCustom") @Autowired public JdbcTemplate jdbcTemplate(@Qualifier("dsCustom") DataSource dsCustom) { return new JdbcTemplate(dsCustom); }}The DAO Class
@Componentpublic class StudentDao { @Autowired @Qualifier("jdbcCustom") private JdbcTemplate jdbcTemplateObject;
public Student getStudent(Integer id) { String SQL = "select * from tbl_student where id = ?"; Student student = jdbcTemplateObject.queryForObject(SQL, new Object[]{id}, new StudentMapper());
return student; }
class StudentMapper implements RowMapper<Student> { public Student mapRow(ResultSet rs, int rowNum) throws SQLException { Student student = new Student(); student.setId(rs.getInt("id")); student.setName(rs.getString("name"));
return student; } }}The JUnit Test Case
@RunWith(SpringRunner.class)@SpringBootTestpublic class TestDefaultDataSource { @Autowired private StudentDao studentDao; @Test public void testSimpleSelect() { Student student = studentDao.getStudent(1); assertNotNull(student); assertEquals(student.getName(),"jack"); }}Running the test case results in a green bar:

The DataSourceBuilder
The DataSourceBuilder class is a convenient way to create a DataSource with common implementations and properties. It supports HikariCP, Tomcat, and Commons DBCP if they are on the classpath. Here is a list of its methods:

Summary
In this post, we explored three different ways to configure data sources in a Spring Boot application:
- Using
application.propertiesfor automatic configuration. - Using
DataSourceBuilderwithapplication.propertiesfor dynamic configuration. - Using
DataSourceBuilderwithout any properties file for fully programmatic configuration.
Each method has its use cases, and the choice depends on the specific requirements of your application. The example code is available on GitHub.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact 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:
- π¨βπ» springboot dynamic datasource routing
- π¨βπ» example codes on github
Oh, and if you found these resources useful, donβt forget to support me by starring the repo on GitHub!