Wednesday, July 3, 2019

Spring Boot Multiple Datasources Configuration

Spring Boot With Multiple Datasources Configuration

In this article we will discuss, how to configure multiple data sources with Spring Boot using Spring Data.
for this we need to create two configuration file for two database and need to do below.
  • DataSource configuration
  • EntityManagerFactory configuration
  • TransactionManager configuration
See below complete example.
Project structure.


Add dependencies in pom.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 
						http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>in.javaiq</groupId>
	<artifactId>SpringBoot-Multiple-Datasources</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>SpringBoot-Multiple-Datasources</name>
	<description>Spring Boot Multiple Datasources With Spring Data</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.1.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</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>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>
Add below in application.properties here we are using two database company_db and employee_db using MYSQL database. As i have only MYSQL on my local. you can also use different database in same way.
# For Datasources-1
spring.datasource.company.url=jdbc:mysql://localhost:3306/company_db
spring.datasource.company.jdbcUrl=${spring.datasource.company.url}
spring.datasource.company.username=root
spring.datasource.company.password=root
spring.datasource.company.platform=mysql
spring.datasource.company.driverClassName = com.mysql.jdbc.Driver

# For Datasources-2
spring.datasource.employee.url=jdbc:mysql://localhost:3306/employee_db
spring.datasource.employee.jdbcUrl=${spring.datasource.employee.url}
spring.datasource.employee.username=root
spring.datasource.employee.password=root
spring.datasource.employee.platform=mysql
spring.datasource.employee.driverClassName = com.mysql.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
Create Model (JPA Entities) : Company.java and Employee.java
package in.javaiq.company.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "company")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Company {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@Column(nullable = false)
	private String name;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Company() {

	}

	public Company(String name) {
		super();
		this.name = name;
	}

	public Company(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	@Override
	public String toString() {
		return "Company [id=" + id + ", name=" + name + "]";
	}

}
package in.javaiq.employee.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "employees")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;

	@Column(nullable = false)
	private String name;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Employee() {

	}

	public Employee(String name) {
		super();
		this.name = name;
	}

	public Employee(Integer id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + "]";
	}

}
Let's Create the JPA repositories for Company and Employee entities. This is used by Spring Data JPA to store data in a relational database. 
Create Repository : EmployeeRepository.java and EmployeeRepository.java
package in.javaiq.company.repo;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import in.javaiq.company.model.Company;

@Repository
public interface CompanyRepository extends CrudRepository<Company, Integer> {

}
package in.javaiq.employee.repo;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import in.javaiq.employee.model.Employee;

@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {

}
Create two Spring db configuration classes who are responsible to create table and read/write from related datasourses.
Create Configuration classes : CompanyDBConfig.java and EmployeeDBConfig.java
package in.javaiq.config;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@EnableJpaRepositories(basePackages = "in.javaiq.company.repo", entityManagerFactoryRef = "companyEntityManagerFactory", transactionManagerRef = "companyTransactionManager")
public class CompanyDBConfig {

	@Bean(name = "companyDataSource")
	@ConfigurationProperties(prefix = "spring.datasource.company")
	public DataSource customerDataSource() {
		return DataSourceBuilder.create().build();
	}

	@Bean(name = "companyEntityManagerFactory")
	public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder,
			@Qualifier("companyDataSource") DataSource dataSource) {
		Map<String, Object> properties = new HashMap<String, Object>();
		// properties.put("hibernate.hbm2ddl.auto", "update");
		// properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
		return builder.dataSource(dataSource).properties(properties).packages("in.javaiq.company.model")
				.persistenceUnit("db1").build();
	}

	@Bean(name = "companyTransactionManager")
	public PlatformTransactionManager customerTransactionManager(
			@Qualifier("companyEntityManagerFactory") EntityManagerFactory customerEntityManagerFactory) {
		return new JpaTransactionManager(customerEntityManagerFactory);
	}

}
package in.javaiq.config;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "in.javaiq.employee", entityManagerFactoryRef = "employeeEntityManagerFactory", transactionManagerRef = "employeeTransactionManager")
public class EmployeeDBConfig {
	@Primary
	@Bean(name = "employeeDataSource")
	@ConfigurationProperties(prefix = "spring.datasource.employee")
	public DataSource customerDataSource() {
		return DataSourceBuilder.create().build();
	}

	@Primary
	@Bean(name = "employeeEntityManagerFactory")
	public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder,
			@Qualifier("employeeDataSource") DataSource dataSource) {
		Map<String, Object> properties = new HashMap<String, Object>();
		// properties.put("hibernate.hbm2ddl.auto", "update");
		// properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
		return builder.dataSource(dataSource).properties(properties).packages("in.javaiq.employee.model")
				.persistenceUnit("db2").build();
	}

	@Primary
	@Bean(name = "employeeTransactionManager")
	public PlatformTransactionManager customerTransactionManager(
			@Qualifier("employeeEntityManagerFactory") EntityManagerFactory customerEntityManagerFactory) {
		return new JpaTransactionManager(customerEntityManagerFactory);
	}
}
Create SpringBootMultipleDatasourcesApplication.java.
package in.javaiq;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import in.javaiq.company.model.Company;
import in.javaiq.company.repo.CompanyRepository;
import in.javaiq.employee.model.Employee;
import in.javaiq.employee.repo.EmployeeRepository;

@SpringBootApplication
@RestController
public class SpringBootMultipleDatasourcesApplication {

	@Autowired
	private CompanyRepository companyRepository;

	@Autowired
	private EmployeeRepository employeeRepository;

	@PostConstruct
	public void saveData() {
		;
		companyRepository
				.saveAll(Stream.of(new Company("Company-1"), new Company("Company-2")).collect(Collectors.toList()));
		employeeRepository.saveAll(
				Stream.of(new Employee("Employee-1"), new Employee("Employee-2")).collect(Collectors.toList()));
	}

	@GetMapping("/getCompanyList")
	public List<Company> getAllCompanys() {
		List<Company> companyes = (List<Company>) companyRepository.findAll();
		return companyes;

	}

	@GetMapping("/getEmployeeList")
	public List<Employee> getAllEmployees() {
		List<Employee> employeess = (List<Employee>) employeeRepository.findAll();
		return employeess;

	}

	public static void main(String[] args) {
		SpringApplication.run(SpringBootMultipleDatasourcesApplication.class, args);
	}

}
Note:- In this article you can see only two confugrations classes files are added than using one datasourses in spring boot.

No comments:

Post a Comment