Saturday, August 12, 2023

How to configure multiple data sources in Spring Boot? Example Tutorial

Spring Boot is a popular framework for building Java applications that simplifies the development process. In some scenarios, you may need to work with multiple databases or data sources in your Spring Boot application. Earlier, we have seen how to change port of spring boot application and in this article will guide you through the process of configuring and using two data sources in Spring Boot. We will explore various approaches and provide practical examples to help you effectively manage multiple data sources in your application.


How can I configure and use two data sources in Spring Boot?

Now, let's deep dive into steps about how to configure and use two different data sources in Spring Boot application.

 

Understanding the Requirement for Multiple Data Sources

There are several situations where you might need to configure and use multiple data sources in your Spring Boot application:

1. Microservices Architecture
In a microservices architecture, each microservice may have its own dedicated database. To ensure separation of concerns and independence, it is necessary to configure multiple data sources.

2. Legacy Database Migration
During the migration process from a legacy system, you might need to connect to both the old and new databases simultaneously to facilitate data migration.

3. Reporting or Analytics
In applications that involve reporting or analytics, it is common to have a separate database optimized for querying and analysis. This database can be used alongside the primary database to offload complex reporting operations.

Now, let's explore the steps to configure and use two data sources in a Spring Boot application.

Step 1: Define Database Configurations

First, define the configurations for each data source in your application.properties or application.yml file.

Example application.properties:

# Data Source 1
spring.datasource.url=jdbc:mysql://localhost:3306/database1
spring.datasource.username=user1
spring.datasource.password=pass1
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
 
# Data Source 2
datasource.secondary.url=jdbc:mysql://localhost:3306/database2
datasource.secondary.username=user2
datasource.secondary.password=pass2
datasource.secondary.driver-class-name=com.mysql.jdbc.Driver

In the above example, we have configured two data sources, datasource and datasource.secondary, each with its own URL, username, password, and driver class name.



Step 2: Define Data Source Beans

Next, define the beans for each data source in your Spring Boot application configuration class.

@Configuration
public class DataSourceConfig {
 
    @Primary
    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
 
    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
}

In the above example, we define two beans, dataSource and secondaryDataSource, corresponding to the two data sources configured in the properties file. The @Primary annotation indicates that the dataSource bean is the primary data source, which will be used by default if a data source is not explicitly specified.



Step 3: Configure JPA or JDBC Templates

Now, you need to configure JPA or JDBC templates to work with the respective data sources.

For JPA:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = "com.example.repository1",
        entityManagerFactoryRef = "entityManagerFactory",
        transactionManagerRef = "transactionManager"
)
public class JpaConfig {
 
    @Autowired
    @Qualifier("dataSource")
    private DataSource dataSource;
 
    @Primary
    @Bean(name = "entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean 
           entityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(dataSource)
                .packages("com.example.entity1")
                .persistenceUnit("primary")
                .build();
    }
 
    @Primary
    @Primary
    @Bean(name = "transactionManager")
    public PlatformTransactionManager 
            transactionManager(EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

In the above example, we configure the JPA template for the primary data source (dataSource) using the entityManagerFactory and transactionManager beans.

For JDBC:

@Configuration
public class JdbcConfig {
 
    @Autowired
    @Qualifier("secondaryDataSource")
    private DataSource secondaryDataSource;
 
    @Bean(name = "secondaryJdbcTemplate")
    public JdbcTemplate secondaryJdbcTemplate() {
        return new JdbcTemplate(secondaryDataSource);
    }
}


In this example, we configure a JdbcTemplate for the secondary data source (secondaryDataSource).



Step 4: Use Data Sources in Application Components

You can now use the configured data sources in your application components, such as repositories or services.

Example Repository:

@Repository
public class UserRepository {
 
    @Autowired
    @Qualifier("entityManagerFactory")
    private EntityManager entityManager;
 
    public User findById(Long id) {
        return entityManager.find(User.class, id);
    }
}

In the above example, the UserRepository uses the primary data source (entityManagerFactory) to fetch a user by ID.

Example Service:

@Service
public class ProductService {
 
    @Autowired
    @Qualifier("secondaryJdbcTemplate")
    private JdbcTemplate jdbcTemplate;
 
    public List<Product> getAllProducts() {
        String sql = "SELECT * FROM products";
        return jdbcTemplate.query(sql, new ProductRowMapper());
    }
}


In this example, the ProductService uses the secondary data source (secondaryJdbcTemplate) to retrieve all products from the "products" table.






Additional Considerations for Working with Multiple Data Sources

Here are few more things which you should keep in mind while working with multiple data sources in a single Spring Boot application: 


1. Transaction Management
When working with multiple data sources, it's important to consider transaction management. Spring provides transaction management capabilities that allow you to manage transactions across multiple data sources. You can annotate your service methods with @Transactional and specify the data source using @Qualifier to ensure that the correct transaction manager is used.
Example:

@Service
public class ProductService {
 
    @Autowired
    @Qualifier("transactionManager")
    private PlatformTransactionManager transactionManager;
 
    @Transactional
    public void performTransactionalOperation() {
        // Perform operations on multiple data sources within a single transaction
    } 
} 



2. Testing Multiple Data Sources
When writing unit tests for components that interact with multiple data sources, you need to ensure that the tests are properly configured to use the desired data sources. You can utilize Spring's testing framework and configure separate test configurations for each data source.
Example Test Configuration:

@Configuration
public class TestConfig {
 
    @Bean(name = "testDataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
 
    @Bean(name = "testSecondaryDataSource")
    @ConfigurationProperties(prefix = "datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
}


3. Externalizing Data Source Configurations
In real-world scenarios, you might want to externalize data source configurations to separate configuration files or environment variables. This approach allows you to change the data source configurations without modifying the application code. Spring Boot provides mechanisms to read externalized configurations, such as using @Value annotations or the @ConfigurationProperties annotation.


4. Connection Pooling
Consider implementing connection pooling for each data source to improve performance and resource utilization. Spring Boot supports various connection pooling libraries like HikariCP, Apache Commons DBCP, and Tomcat JDBC Pool. You can configure and customize the connection pool settings in the data source configurations.

Conclusion

That's all about how to configure multiple data sources in a single Spring Boot application in Java. Configuring and using two data sources in a Spring Boot application allows you to work with multiple databases efficiently. By following the steps outlined in this article, you can define the database configurations, create data source beans, configure JPA or JDBC templates, and utilize the data sources in your application components. 

Whether you are working with microservices, performing database migrations, or dealing with reporting/analytics requirements, Spring Boot provides the necessary tools to handle multiple data sources effectively. Proper configuration and usage of multiple data sources enable you to build robust and scalable applications that meet your specific data management needs.

Other Spring MVC articles and Tutorials you may like
Thanks a lot for reading this article so far. If you like this Java and Spring Boot tutorial then please share them with your friends and colleagues. If you have any questions or feedback then please drop a note. 

No comments:

Post a Comment

Feel free to comment, ask questions if you have any doubt.