728x90
반응형

 

프로젝트를 진행하는데 기존 시스템이 있는곳이라 DB를 2개 이상 사용해야된다고 합니다.

 

이제 Spring Boot 2.x 를 공부겸 진행하고 있는데 매번 난관이군요.

 

늘 생각하는거지만 실제론 쉬운 코드인데 엄청 어렵게 설명되어있는 글들이 많네요.

 

일단 제가 작성한대로 정리해보겠습니다.

 

 

 

 

 

 

Packacge 구조

다중 DB를 사용할 때에는 package 로 구분하게 됩니다.

 

customer 와 user 로 분류하여 진행하도록 하겠습니다.

-com
    -project
        - customer
            - config
                - CustomerDataSourceConfig.java
            - domain
                - Customer.java
            - repository
                - CustomerRepository.java
        -user
            - config
                - UserDataSourceConfig.java
            - domain
                - User.java
            - repository
                - UserRepository.java
        DataSourceProperties.java
 

 

 

application.yml

Oracle을 사용하기에 JDBC jar를 등록하여 사용했습니다.

 

https://gigas-blog.tistory.com/112

 

[Spring] Gradle 외부 Jar 등록

Spring Boot Project 를 만들면 Maven 이나 Gradle이 기본적으로 설치되어있습니다. 다양한 library 을 쉽고 간편하게 가져와서 쓸수 있지만 외부와의 통신을 허용하지 않는 개발 환경이 있기도 합니다. 이럴때에..

gigas-blog.tistory.com

SpringBoot 2.x 부터 기본 jdbc 로 hikari를 사용하고 있기 때문에 url 이 아닌 jdbc-url로 수정해 주어야 합니다.

 

url 과 driver-class-name, username, password 는 db에 맞는 정보로 수정해야 합니다.

 

customer 와 user 이렇게 2개로 분리하였습니다.

server:
  port: 9099


spring:
  datasource:
    hikari:
      customer:
        jdbc-url: jdbc:oracle:thin:@localhost:1521:xe
        username: -
        password: -
        driver-class-name: oracle.jdbc.OracleDriver
        
      user:
        jdbc-url: jdbc:oracle:thin:@-:-
        username: -
        password: -
        driver-class-name: oracle.jdbc.OracleDriver
 

 

 

DataSourceProperties.java

공통적인 DataSource 부분은 한곳에 정의하였습니다.

 

@Bean 으로 등록할 때 이름을 지정해주어 사용하려고 name을 등록해주었습니다.

 

@Qualifier 로 객체를 선택할 수 있도록 지정해 줍니다.

 

@Primary 주가 되는 DataSource를 지정해 줍니다.

 

@ConfigurationProperties yml이나 properties 속성을 지정해 줍니다.

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import com.zaxxer.hikari.HikariDataSource;

@Configuration
@EnableConfigurationProperties
public class DataSourceProperties {
    
    @Bean(name = "customerDataSource")
    @Qualifier("customerDataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.hikari.customer")
    public DataSource customerDataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }
    
    @Bean(name = "userDataSource")
    @Qualifier("userDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.hikari.user")
    public DataSource userDataSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }
}

 

 

Customer.java

User.java 와 동일합니다.

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

import lombok.Data;

@Entity
@Data
@Table(name = "CUSTOMER")
public class Customer {

  @Id
  @Column(name = "컬럼명")
  private  String column1;

  @Column(name = "컬럼명")
  private String column2;

}
 

 

 

CustomerRepository.java

CustomerRepository 입니다.

import org.springframework.data.jpa.repository.JpaRepository;

import com.project.customer.domain.Customer;

public interface CustomerRepository extends JpaRepository<Customer, Long>{

}

 

 

 

CustomerDataSourceConfig.java

주가 되는 Customer 입니다.

 

User와는 @Primary 차이만 있을뿐 기본적인 설정은 같습니다.

 

@EnableJpaRepositories의 basePackages 는 repository 경로를 설정해주면 됩니다.

 

customerEntityManagerFactory 의 packages 는 domain 경로를 설정해주면 됩니다.

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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(
        entityManagerFactoryRef = "customerEntityManagerFactory", 
        transactionManagerRef = "customerTransactionManager", 
        basePackages = { "com.project.customer.repository" })
public class CustomerDataSourceConfig {
    
    @Autowired
    @Qualifier("customerDataSource")
    private DataSource customerDataSource;
    
    @Primary
    @Bean(name = "customerEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean customerEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(customerDataSource)
                .packages("com.project.customer.domain")
                .persistenceUnit("customer")
                .build();
    }
    
    @Primary
    @Bean("customerTransactionManager")
    public PlatformTransactionManager customerTransactionManager(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(customerEntityManagerFactory(builder).getObject());
    }

}

 

 

 

User.java

User.java 를 생성하였습니다.

 

테이블명과 컬럼명, 변수명은 DB에 맞게 맞춰주면 됩니다.

 

필요에 맞게  @GeneratedValue(strategy=GenerationType.AUTO) 를 생성해주시면 됩니다.

import javax.persistence.Column;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;

@Entity
@Data
@Table(name = "USER")
public class User {

  @Id
  @Column(name = "컬럼명")
  private  String column1;

  @Column(name = "컬럼명")
  private String column2;

}

 

 

UserRepository.java

UserRepository 입니다.

import org.springframework.data.jpa.repository.JpaRepository;

import com.project.user.domain.User;

public interface UserRepository extends JpaRepository<User, String>{

}

 

 

UserDataSourceConfig.java

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "userEntityManagerFactory", 
        transactionManagerRef = "userTransactionManager", 
        basePackages = { "com.project.user.repository" })
public class UserDataSourceConfig {

    @Autowired
    @Qualifier("userDataSource")
    private DataSource userDataSource;

    @Bean(name = "userEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean userEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(userDataSource)
                .packages("com.project.user.domain")
                .persistenceUnit("user")
                .build();
    }

    @Bean("userTransactionManager")
    public PlatformTransactionManager userTransactionManager(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(userEntityManagerFactory(builder).getObject());
    }
}

 

 

 

 

@Primary 설정으로 @Transactional 처리의 기준이 됩니다.

 

기본 설정이 아닌 DB 의 Transaction을 처리 하려면 @Transactional(value = "userTransactionManager") 이런식으로 사용하면 됩니다.

 

간단하게 test를 해보았습니다.

 

각각의 package의 기준으로 분리된 db 를 조회해서 정상적으로 출력이 된다면 잘 적용된것을 알 수 있습니다.

 

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.project.customer.repository.CustomerRepository;
import com.project.user.repository.UserRepository;

import lombok.extern.slf4j.Slf4j;

@RunWith(SpringRunner.class)
@Slf4j
@SpringBootTest
public class SpringBootMultipleJpaApplicationTests {
    
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private CustomerRepository customerRepository;

    @Test
    public void userTest() {
        userRepository.findAll()
            .stream()
            .map(i -> i.toString())
            .forEach(log::info);
    }

    @Test
    public void custoemrTest(){
        customerRepository.findAll()
            .stream()
            .map(i -> i.toString())
            .forEach(log::info);
    }
}
 

 

 

 

부가적으로 설명해야할 부분이 많지만 기본적인 지식을 갖고 있는 분을 기준으로 작성했으며 다른 속성들은 문의 주시면 감사하겠습니다.

 

728x90
반응형

+ Recent posts