• notice
  • Congratulations on the launch of the Sought Tech site

Configure and use multiple data sources in Spring Boot

I. Overview

A typical scenario for a Spring Boot application is to store data in a single relational database. But sometimes, we need to access multiple databases.

In this tutorial, we will learn how to configure and use multiple data sources with Spring Boot. To understand how to work with a single data source, we can read our article on Introduction to Spring Data JPA.

2. Default behavior

We know that declaring a data source in Spring Boot looks like in application.yml:

spring:
datasource:
url: ...
username: ...
password: ...
driverClassname: ...

Internally, Spring maps these settings to org.springframework.boot.autoconfigure.jdbc.DataSourcePropertiesan instance of . Let's look at the implementation:

@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
// ...
/**
* Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.
*/
private String driverClassName;
/**
* JDBC URL of the database.
*/
private String url;
/**
* Login username of the database.
*/
private String username;
/**
* Login password of the database.
*/
private String password;
// ...
}

We should point out @ConfigurationPropertiesthe annotation, which automatically maps configured properties to Java objects.

3. Extended defaults

Therefore, to use multiple data sources, we need to declare multiple beans with different mappings in Spring's application context.

We can do this by using the configuration class:

@Configuration
public class TodoDatasourceConfiguration {
@Bean
@ConfigurationProperties("spring.datasource.todos")
public DataSourceProperties dataSourceProperties1() {
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties("spring.datasource.topics")
public DataSourceProperties dataSourceProperties1() {
return new DataSourceProperties();
}
}

The configuration of the data source must look like this:

spring:
datasource:
todos:
url: ...
username: ...
password: ...
driverClassName: ...
topics:
url: ...
username: ...
password: ...
driverClassName: ...

Then, we can use the DataSourcePropertiesobject to create the data source:

@Bean
public DataSource todosDataSource() {
return todosDataSourceProperties()
.initializeDataSourceBuilder()
.build();
}
@Bean
public DataSource topicsDataSource() {
return topicsDataSourceProperties()
.initializeDataSourceBuilder()
.build();
}

4. Spring Data JDBC

When using Spring Data JDBC, we also need to DataSourceconfigure an JdbcTemplateinstance for each:

@Bean
public JdbcTemplate todosJdbcTemplate(@Qualifier("todosDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public JdbcTemplate topicsJdbcTemplate(@Qualifier("topicsDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}

Then we can also @Qualifieruse them by specifying:

@Autowired
@Qualifier("topicsJdbcTemplate")
JdbcTemplate jdbcTemplate;

5. Spring Data JPA

When using Spring Data JPA, we want to use a repository like this, where Todoare entities:

public interface TodoRepository extends JpaRepository<Todo, Long> {}

Therefore, we need to declare EntityManagerfactories for each data source:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackageClasses = Todo.class,
entityManagerFactoryRef = "todosEntityManagerFactory",
transactionManagerRef = "todosTransactionManager"
)
public class TodoJpaConfiguration {
@Bean
public LocalContainerEntityManagerFactoryBean todosEntityManagerFactory(
Qualifier("todosDataSource") DataSource dataSource,
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(todosDataSource())
.packages(Todo.class)
.build();
}
@Bean
public PlatformTransactionManager todosTransactionManager(
@Qualifier("todosEntityManagerFactory") LocalContainerEntityManagerFactoryBean todosEntityManagerFactory) {
return new JpaTransactionManager(Objects.requireNonNull(todosEntityManagerFactory.getObject()));
}
}

We need to be aware of the following limitations.

We need to split the package to allow one for each data source @EnableJpaRepositories.

Unfortunately, to inject EntityManagerFactoryBuilder, we need to declare one of the data sources as @Primary. This is because it EntityManagerFactoryBuilderis org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfigurationdeclared in and this class needs to inject a single data source. Often, some parts of the framework may not expect multiple data sources to be configured.

VI. CONCLUSION

In this article, we learned how to configure multiple data sources with Spring Boot. We've seen that we need some configuration and that there can be pitfalls when deviating from the standard - but in the end, we can see that it's possible.


Tags

Technical otaku

Sought technology together

Related Topic

0 Comments

Leave a Reply

+