Open In App

Configure Multiple Datasource in Spring Boot Application

Last Updated : 20 Mar, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Sometimes we build some applications that need multiple databases. Our data is arranged to store multiple databases, like one database designed for another need or another database for another need. So, in this article, we will see how to configure multiple in the Spring Boot application.

Note: We are using MySQL 8 workbench for both the database.

Steps to Configure Multiple Datasourse in Spring Boot Application

Below are the steps to configure multiple Datasource in the Spring Boot application.

Step 1: First, we need to configure the Properties file.

application.properties:

# DataSource configuration
#DB1
spring.datasource.url=jdbc:mysql://localhost:8084/db1
spring.datasource.username=root
spring.datasource.password=tisha
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#DB2
second.datasource.url=jdbc:mysql://localhost:8084/db2
second.datasource.username=root
second.datasource.password=tisha
second.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA (Java Persistence API) configuration
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
# create,update,delete
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

Step 2: Now, we will configure Dependency in pom.xml file.

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.techous</groupId>
    <artifactId>Trigger-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Trigger-demo</name>
    <description>master slave project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Project Structure:

Below we can see the Project structure after designing multiple datasources.

Project Structure


First, we made database 1 configuration according to above image.

Db1Config.java:

Java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "firstEntityManagerFactoryBean",
        basePackages = {"org.techous.triggerdemo.db1.repository"},
        transactionManagerRef = "firstTransactionManager"
)
public class Db1Config {

    @Autowired
    private Environment environment;

    @Bean(name = "firstDataSource")
    @Primary
    public DataSource dataSource(){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl(environment.getProperty("spring.datasource.url"));
        dataSource.setDriverClassName(environment.getProperty("spring.datasource.driver-class-name"));
        dataSource.setUsername(environment.getProperty("spring.datasource.username"));
        dataSource.setPassword(environment.getProperty("spring.datasource.password"));

        return dataSource;
    }

    @Primary
    @Bean(name = "firstEntityManagerFactoryBean")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){
        LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
        bean.setDataSource(dataSource());
        bean.setPackagesToScan("org.techous.triggerdemo.db1.model");

        JpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        bean.setJpaVendorAdapter(adapter);

        Map<String,String> props = new HashMap<>();
        props.put("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
        props.put("hibernate.show_sql","true");
        props.put("hibernate.hbm2ddl.auto","update");
        bean.setJpaPropertyMap(props);

        return bean;
    }

    @Bean(name = "firstTransactionManager")
    @Primary
    public PlatformTransactionManager transactionManager(){
        JpaTransactionManager manager = new JpaTransactionManager();
        manager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
        return manager;
    }
}


In above code, we are doing add configuration for calling db1. We are using @configuration annotation in this class and the class become a bean. Here we use Environment class for configure internal environment then use Datasourse for making different database configuration. Then use LocalContinerEntityManager to set what package scan and run first whatever path we have provided this considered database and store all data there. This configuration is used only for making multiple datasourse here. Rest of things as it is like simple crud operation we are done.

ProductController.java:

Java
package org.techous.triggerdemo.db1.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.techous.triggerdemo.db1.model.Product;
import org.techous.triggerdemo.db1.service.ProductService;

// Controller class for handling product-related requests
@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductService productService;

    // Endpoint for saving a product
    @PostMapping("saveProduct")
    public ResponseEntity<Product> saveProduct(@RequestBody Product product){
        Product myproduct = productService.saveProduct(product);
        return new ResponseEntity<>(myproduct, HttpStatus.OK);
    }

}

The above class is service class endpoint for calling APIs.

ProductService.java:

Java
package org.techous.triggerdemo.db1.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.techous.triggerdemo.db1.model.Product;
import org.techous.triggerdemo.db1.repository.ProductRepo;

// Service class for product-related operations
@Service
public class ProductService {

    @Autowired
    private ProductRepo productRepo;

    // Method to save a product
    public Product saveProduct(Product product) {
        return productRepo.save(product);
    }
}

The above class is productService class for making all business logic here.

Product.java:

Java
package org.techous.triggerdemo.db1.model;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

// Entity class for Product
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "product")
public class Product {

    @Id
    private int productId;
    private String name;
    private int price;
}

The above class is our entity class.

ProductRepo.java:

Java
package org.techous.triggerdemo.db1.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.techous.triggerdemo.db1.model.Product;

// Repository interface for Product
@Repository
public interface ProductRepo extends JpaRepository<Product,Integer> {

}


This above class is our repository to save anythings.

This is the Configuration of database 1 (db1).

Now, we will do another database (db2) configuration below.

Db2Config2.java:

Java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "secondEntityManagerFactoryBean",
        basePackages = {"org.techous.triggerdemo.db2.repository"},
        transactionManagerRef = "secondTransactionManager"
)
public class Db2Config {

    @Autowired
    private Environment environment;

    @Bean(name = "secondDataSource")
    public DataSource dataSource(){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl(environment.getProperty("second.datasource.url"));
        dataSource.setDriverClassName(environment.getProperty("second.datasource.driver-class-name"));
        dataSource.setUsername(environment.getProperty("second.datasource.username"));
        dataSource.setPassword(environment.getProperty("second.datasource.password"));

        return dataSource;
    }

    @Bean(name = "secondEntityManagerFactoryBean")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){
        LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
        bean.setDataSource(dataSource());
        bean.setPackagesToScan("org.techous.triggerdemo.db2.model");

        JpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        bean.setJpaVendorAdapter(adapter);

        Map<String,String> props = new HashMap<>();
        props.put("hibernate.dialect","org.hibernate.dialect.MySQLDialect");
        props.put("hibernate.show_sql","true");
        props.put("hibernate.hbm2ddl.auto","update");
        bean.setJpaPropertyMap(props);

        return bean;
    }

    @Bean(name = "secondTransactionManager")
    public PlatformTransactionManager transactionManager(){
        JpaTransactionManager manager = new JpaTransactionManager();
        manager.setEntityManagerFactory(entityManagerFactoryBean().getObject());
        return manager;
    }
}

As per saying above, same configuration made here also and define properties path as per our database design. (only change in package URL)

UserController.java:

Java
package org.techous.triggerdemo.db2.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.techous.triggerdemo.db2.model.User;
import org.techous.triggerdemo.db2.service.UserService;

@RestController
@RequestMapping("/api")
public class UserController {

    @Autowired
    private UserService userService;

    // Endpoint to save a user
    @PostMapping("/saveUser")
    public ResponseEntity<User> save(@RequestBody User user){
        User myuser = userService.saveUser(user);
        return new ResponseEntity<>(myuser, HttpStatus.OK);
    }

}


UserService.java:

Java
package org.techous.triggerdemo.db2.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.techous.triggerdemo.db2.model.User;
import org.techous.triggerdemo.db2.repository.UserRepository;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    // Service method to save a user
    public User saveUser(User user) {
        return userRepository.save(user);
    }
}


User.java:

Java
package org.techous.triggerdemo.db2.model;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int userId; // Unique identifier for the user

    private String name; // Name of the user

    private int age; // Age of the user
}

UserRepository.java:

Java
package org.techous.triggerdemo.db2.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.techous.triggerdemo.db2.model.User;

@Repository
public interface UserRepository extends JpaRepository<User,Integer> {
}

We have completed all our database configuration.

Now, when we insert user, it will save in db2 database and when we save product, it will save in db1.

Databases


Output:

First, we will add User.

Add User

In the below screen, we can see the user added to the database.

User added

Now, we will add Product.

Add Product

Now, we can see the product added to the database.

Product added

This way we can Configure Multiple DataSource in a single Spring Boot application.


Next Article

Similar Reads