본문 바로가기

Programming!

Spring Boot 에 HikariCp / JPA / Multiple DataSources 적용해보기

최근의 Spring Boot 은 여기 참조..

https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-access.configure-two-datasources

 

“How-to” Guides

Spring Boot has no mandatory logging dependency, except for the Commons Logging API, which is typically provided by Spring Framework’s spring-jcl module. To use Logback, you need to include it and spring-jcl on the classpath. The recommended way to do th

docs.spring.io

 

이건 예전 내용

--------------------------------
기존 운영중인 서비스를 java 로 변경하면서 플젝을 세팅하다보니 서비스 운영 데이터 DB와 계정 정보 DB가 분리되어 있는 걸 확인했다. 아...

 

Spring Security를 적용해 로그인 처리를 하기 위해서는 계정 DB(backoffice)에 사용해야 하고 그외에는 서비스 운영 데이터 DB(selleroffice)를 바라보도록 하는 것으로 정하고 세팅을 진행함.

 

기존 소스를 유지하며, 두개의 Datasource를 만들자.

 

File : application.properties

backoffice.datasource.jdbc-url=jdbc:mysql://localhost:3306/backoffice?useSSL=false

backoffice.datasource.username=master

backoffice.datasource.password=my.local

backoffice.datasource.driver-class-name=com.mysql.jdbc.Driver

backoffice.datasource.type=com.zaxxer.hikari.HikariDataSource

 

spring.datasource.jdbc-url=jdbc:mysql://localhost:3306/selleroffice?useSSL=false

spring.datasource.username=master

spring.datasource.password=my.local

spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.datasource.type=com.zaxxer.hikari.HikariDataSource

 

spring.jpa.show-sql = true

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

....

 

 

Backoffice DataSource : HikariCpBackofficeDataSource.java

@Configuration

@EnableTransactionManagement

@EnableJpaRepositories(basePackages = {"xxx.pelican.repository.backoffice", "xxx.pelican.entity.backoffice"},

        transactionManagerRef = "backofficeTransactionManager", entityManagerFactoryRef = "backofficeEntityManagerFactory")

public class HikariCpBackofficeDataSource {

 

    @Bean(name = "backofficeDataSource")

    @ConfigurationProperties(prefix = "backoffice.datasource")

    public DataSource backofficeDataSource() throws SQLException {

        HikariDataSource hikariDataSource = new HikariDataSource();

        return hikariDataSource;

    }

 

    @Bean(name = "backofficeEntityManagerFactory")

    public LocalContainerEntityManagerFactoryBean backofficeEntityManagerFactory(EntityManagerFactoryBuilder builder, @Qualifier("backofficeDataSource") DataSource dataSource) {

        return builder.dataSource(dataSource).packages("xxx.pelican.repository.backoffice", "xxx.pelican.entity.backoffice").build();

    }

 

    @Bean(name = "backofficeTransactionManager")

    public PlatformTransactionManager backofficeTransactionManager(@Qualifier("backofficeEntityManagerFactory") EntityManagerFactory entityManagerFactory) {

        return new JpaTransactionManager(entityManagerFactory);

 

    }

 

}

 

Auth DataSource : HikariCpSellerDataSource.java

@Configuration

@EnableTransactionManagement

@EnableJpaRepositories(basePackages = {"xxx.pelican.repository.selleroffice", "xxx.pelican.entity.selleroffice"})

public class HikariCpSellerDataSource {

 

    @Autowired

    private HikariConfig pelicanhikariConfig;

    

    

    @Bean

    @Primary

    @ConfigurationProperties(prefix = "spring.datasource")

    public DataSource sellerofficeDataSource() throws SQLException {

        HikariDataSource hikariDataSource = new HikariDataSource();

        return hikariDataSource;

    }

    

    @Primary

    @Bean(name = "entityManagerFactory")

    public LocalContainerEntityManagerFactoryBean sellerofficeEntityManagerFactory(EntityManagerFactoryBuilder builder, @Qualifier("sellerofficeDataSource") DataSource dataSource) {

        return builder.dataSource(dataSource).packages("xxx.pelican.repository.selleroffice", "xxx.pelican.entity.selleroffice").build();

    }

 

    @Primary

    @Bean(name = "transactionManager")

    public PlatformTransactionManager sellerofficeTransactionManager(@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {

        return new JpaTransactionManager(entityManagerFactory);

    }

}

 

코드를 보면 알겠지만 기본적으로 분기처리는 package에 의해 처리된다. 

기본 서비스용 DB로 사용되는 DataSource에는 @Primary를 지정 하고, properties 의 prefix도  "spring.datasource"로 지정, 계정 관리로 사용되는 DataSource의 properties prefix는 "backoffice.datasource"로 지정했다.

 

 

이후 Repository나 Entity를 지정된 package에 맞춰 생성하면 해당 datasource를 사용하게 된다.

여기까지가 다중 DataSource를 사용하는 부분이고... 

 

막상 hikaricp를 쓰는데 pool에 대한 각 properties를 지정할 수가 없었다. 예로 "spring.datasource.hikari.idle-timeout" 와 같은..

 

DataSourceBuilder 사용으로도 처리가 안되고... 다른 문제가 있는건지  좀 더 파고 들어야 겠지만 우선 커넥션 관련 DataSource는 문제 없으니, 공통적인 부분은 HikariConfig로 따로 관리 하기로 했다.

 

우선 HikariConfig관련 Properties를 따로 빼고

@Configuration

public class HikariCpProperties {

 

    @Bean

    public HikariConfig pelicanhikariConfig() throws Exception {

        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

        Resource resource = resolver.getResource("classpath:hikaricp.properties");

        Properties loadProperties = PropertiesLoaderUtils.loadProperties(resource);

        HikariConfig hikariConfig = new HikariConfig(loadProperties);

        return hikariConfig;

    }

}

 

hikaricp.properties에 각종 공통으로 사용되는 설정 옵션을 지정한다.

poolName=HikariConnectionPool

minimumIdle=20

maximumPoolSize=30

idleTimeout=250000

maxLifetime=290000

validationTimeout=10000

 

 

요로코럼 해서 DataSource생성시 설정을 각각 set 처리해주면 된다. HikariCpDataSource생성시 config를 parameter로 넘기면 jdbc-url이 null처리 되므로 속성을 개별적으로 지정해주자.

 

끄윽.