일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- IntelliJ
- superBuilder
- DevOps
- CI/CD
- 알고리즘
- CKA
- ORM
- 뷰
- k8s
- JPA
- 코딩테스트연습
- Vue
- docker
- Spring
- cd
- Oracle
- CI
- map
- 프로그래머스
- 해시맵
- java
- programmers
- dabase
- SpringMVC
- Kubernetes
- builder-pattern
- hibernate
- 자바
- Di
- vuejs
Archives
- Today
- Total
문홍의 공부장
@Primary 와 @Qualifier (2) - 활용편: 2개 이상의 데이터베이스 연결하기 본문
반응형
앞선 @Primary 와 @Qualifier (1) - 기본편 에서, 어노테이션의 기능과 사용법에 대하여 알아보았다. 이 내용을 바탕으로, 최근 실무에 적용하였던 사례를 정리해보고자 한다.
최근 multiple database 를 구성하는 태스크가 있어, 두 개의 데이터베이스 중 하나를 메인 DB 로, 다른 하나를 서브 DB 로 정의하여 환경을 구성하였다.
데이터베이스 스키마에 따라 myBatis 와 JPA 를 분리하여 사용하는 것으로 하였다. 이에 따라 메인 DB 는 myBatis mapper 를 스캔할 수 있도록 하는 설정을 추가하고, 서브 DB 에는 entityManager 에 대한 설정을 추가하였다.
1. 메인 DB 의 DataSource 설정
- 메인 데이터베이스 커넥션에 @Primary 를 사용하여 default 로 설정한다
- 메인 데이터베이스에 대한 property 를 읽을 수 있도록
@ConfigurationProperties
를 설정한다 - 패키지 디렉토리 (
repository
) 에 있는 모든 파일을 Mapper 로 읽어들일 수 있도록@MapperScan
어노테이션에 베이스 패키지를 추가한다
@Configuration
@MapperScan(
basePackages = {
"com.sample.myapp.aaa.*.repository"
})
public class DataSourceConfiguration {
@ConfigurationProperties(prefix = "spring.datasource.main-db")
@Bean
@Primary
public DataSource mainDbDataSource() {
return DataSourceBuilder.create().build();
}
}
2. 서브 DB 의 DataSource 설정
- 서브 데이터베이스 커넥션에 @Qualifier 로 특정하여 명시적으로 의존성을 주입받아 사용할 수 있도록 한다
- 서브 데이터베이스에 대한 property 를 읽을 수 있도록
@ConfigurationProperties
를 설정한다 - JPA 의 트랜잭션 매니저를 설정하기 위해 EntityManager, JpaTransactionManager 빈을 생성한다.
@EnableJpaRepositories
- JPA Repository들을 활성화하기 위한 어노테이션
- 기본적으로 해당 Config 클래스의 하위 패키지를 스캔하며, 특정 패키지의 파일만 스캔하도록 하기 위해 베이스 패키지를 설정하였다
- 설정한 패키지게 있는 파일을 JPA Repository 로 생성한다
- EntityManager 생성
@Qualifier
로 특정하여, 서브DB 의 datasource 를 이용하여 LocalContainerEntityManagerFactoryBean 을 생성한다- 이 때, packages() 에 Entity 로 생성할 클래스 파일을 관리하는 패키지를 베이스 패키지로 설정한다
@EnableJpaRepositories
의 베이스 패키지는 JPA Repository 생성 대상을 설정하며EntityManager
의 베이스 패키지는 Entity 생성 대상을 설정한다는 점에 주의하자
- set JpaPropertyMap
- property 파일에 JPA 관련 프로퍼티를 설정하였으나, multiple datasource 설정을 하며 해당 프로퍼티를 읽지 못하는 이슈가 발생했다
- EntityManager 를 직접 생성해주어야 함에 따라, JPA properties 역시 직접 설정해주어야 하는 것으로 확인하였다
- 이에 property 값을 읽어와 소스 레벨에서 값을 set 하여 주었다
- JpaTransactionManager 생성
- EntityManager 와 마찬가지로, JpaTransactionManager 역시 직접 빈을 생성해주어야 한다
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = {"com.sample.myapp.bbb.*.repository"},
entityManagerFactoryRef = "subDbEntityManagerFactory",
transactionManagerRef = "subDbTransactionManager")
@RequiredArgsConstructor
public class DataSourceConfiguration {
private final Environment env;
@ConfigurationProperties(prefix = "spring.datasource.sub-db")
@Bean
public DataSource subDbDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public LocalContainerEntityManagerFactoryBean subDbEntityManagerFactory(
@Qualifier("subDbDataSource") DataSource dataSource, EntityManagerFactoryBuilder builder) {
LocalContainerEntityManagerFactoryBean em =
builder
.dataSource(dataSource)
.packages(
"com.sample.myapp.bbb.*.repository.domain")
.build();
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaPropertyMap(
Map.of(
"hibernate.dialect",
env.getProperty("spring.jpa.database-platform"),
"hibernate.hbm2ddl.auto",
env.getProperty("spring.jpa.hibernate.ddl-auto"),
"hibernate.physical_naming_strategy",
env.getProperty("spring.jpa.hibernate.physical_naming_strategy"),
"hibernate.show_sql",
env.getProperty("spring.jpa.properties.hibernate.show_sql"),
"hibernate.format_sql",
env.getProperty("spring.jpa.properties.hibernate.format_sql"),
"hibernate.default_batch_fetch_size",
env.getProperty("spring.jpa.properties.hibernate.default_batch_fetch_size")));
return em;
}
@Bean
public PlatformTransactionManager subDbTransactionManager(
@Qualifier("subDbEntityManagerFactory")
LocalContainerEntityManagerFactoryBean entityManagerFactory) {
return new JpaTransactionManager(Objects.requireNonNull(entityManagerFactory.getObject()));
}
}
3. application.yml 설정
spring:
datasource:
main-db:
jdbc-url: #{DB_URL}
username: #{USERNAME}
password: #{PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
sub-db:
jdbc-url: #{DB_URL}
username: #{USERNAME}
password: #{PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
database-platform: org.hibernate.dialect.MySQL57Dialect
hibernate:
ddl-auto: none
physical_naming_strategy: com.sample.myapp.config.UppercaseSnakePhysicalNamingStrategy
properties:
hibernate:
show_sql: true
format_sql: true
default_batch_fetch_size: 100
mybatis:
mapper-locations: mapper/**/*.xml
configuration:
map-underscore-to-camel-case: true
References.
반응형
'개발 > Spring' 카테고리의 다른 글
[Java/Spring] Event publish & Listener (0) | 2024.03.09 |
---|---|
[Spring] ResponseBodyAdvice 를 이용하여 ControllerAdvice 활용하기 (1) | 2024.01.24 |
[Spring] @Primary 와 @Qualifier 비교하고 이해하기 (0) | 2023.04.18 |
[Spring/Java] 회원가입 이메일 인증 구현하기 (13) | 2020.03.31 |
[Spring] 스프링 핵심 개념: Ioc(제어의 역전)과 DI(의존성 주입) (0) | 2020.02.07 |