일상적 이야기들.

Multi Database Source. 본문

프로그래밍/JAVA&SPRING

Multi Database Source.

noveljava 2023. 8. 24. 22:14

Multi Database Source.

설정

Gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.0'
    id 'io.spring.dependency-management' version '1.1.0'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

repositories {
    mavenCentral()
}

ext {
    set('springShellVersion', "3.1.1")
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'

    runtimeOnly 'com.h2database:h2'
    // mysql

    annotationProcessor 'org.projectlombok:lombok'
    implementation 'com.mysql:mysql-connector-j:8.0.33'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.shell:spring-shell-dependencies:${springShellVersion}"
    }
}

tasks.named('test') {
    useJUnitPlatform()
}

mysql, h2 관련드라이버 설치 필요

  • runtimeOnly 'com.h2database:h2'
  • implementation 'com.mysql:mysql-connector-j:8.0.33'

application.yml

# Database configuration
spring:
  datasource-h2:
    driver-class-name: org.h2.Driver
    jdbcUrl: jdbc:h2:~/jpa_study
    username: sa
    password:

  h2:
    console:
      enabled: true
      path: /h2-console

  datasource-mysql:
    driver-class-name: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://localhost:3306/jpa_study
    username: root
    password: ysson
  • datasource-h2
  • datasource-mysql

h2와 mysql 용 datasource를 분리해둠.

  • 각 항목에는 DB접속과 관련된 정보들이 들어가있음.

  • 단일 구성 시에, url 로 사용이 되었는데, 여러개로 구성시에는 jdbcUrl 로 사용되어야 인식이 가능하므로 조심해야함.

Configuration Code

package com.example.cwahell.configure;

import org.springframework.boot.context.properties.ConfigurationProperties;
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 org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
@EnableJpaRepositories (
        basePackages = "com.example.cwahell.excel.application.h2.repository",
        entityManagerFactoryRef = "h2EntityManager",
        transactionManagerRef = "h2TransactionManager"
)
public class H2DataSourceConfig {
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean h2EntityManager() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(h2DataSource());
        em.setPackagesToScan("com.example.cwahell.excel.application");

        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        Properties jpaProperties = new Properties();
        jpaProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        jpaVendorAdapter.setShowSql(true);

        em.setJpaVendorAdapter(jpaVendorAdapter);
        em.setJpaProperties(jpaProperties);

        return em;
    }

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource-h2")
    public DataSource h2DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public PlatformTransactionManager h2TransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();

        transactionManager.setEntityManagerFactory(h2EntityManager().getObject());

        return transactionManager;
    }
}
package com.example.cwahell.configure;

import com.zaxxer.hikari.HikariDataSource;
import jakarta.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
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.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
@EnableJpaRepositories (
        basePackages = "com.example.cwahell.excel.application.mysql.repository",
        entityManagerFactoryRef = "mysqlEntityManager",
        transactionManagerRef = "mysqlTransactionManager"
)

public class MySQLDataSourceConfig {
    @Bean
    public LocalContainerEntityManagerFactoryBean mysqlEntityManager() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(mysqlDataSource());
        em.setPackagesToScan("com.example.cwahell.excel.application");

        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        Properties jpaProperties = new Properties();
        jpaProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
        jpaVendorAdapter.setShowSql(true);

        em.setJpaVendorAdapter(jpaVendorAdapter);
        em.setJpaProperties(jpaProperties);

        return em;
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource-mysql")
    public DataSource mysqlDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public PlatformTransactionManager mysqlTransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();

        transactionManager.setEntityManagerFactory(mysqlEntityManager().getObject());

        return transactionManager;
    }
}
  • 왼쪽 : Primary 로 설정
    • 빈 이름을 별도로 설정하지 않을 경우에는 @Primary 설정된 빈을 자동으로 Autowired 합니다.
  • 오른쪽 : 일반적으로 설정

LocalContainerEntityManagerFactoryBean

Java에서 제공되는 @Repository는 Entity Manager 를 확장하여 사용되는 구조이다.

Jpa의 근간은 Entity Manager 로 구성이 되어있으며, EntityManager는 엔티티를 CRUD 등 엔티티와 관련된 모든 일을 처리한다.

그렇기에 Muti Database를 사용할 시에, EntityManager에서 어떠한 DB를 사용할 것인지, 어떠한 Dialect(방언)을 사용할 것이며, DB에 전반적인 속성을 셋팅해줘야한다.

또한, Entity를 Scan해야하므로 Entity의 위치 또한 알려줘야한다.

  • setPackagesToScan : Entity 들을 찾기 위한 경로.
    • 해당 기능을 통해서 Repository 와 Entity 의 환경을 격리 시켜줄 수 있을 것이라 판단이 된다.

DataSource

application.yml 파일에 기재된 정보를 읽어오는 위치이다.

  • prefix를 통하여 어떠한 정보를 읽을지에 대해서 선택한다.

PlatformTransactionManager

Comments