1. application.yml 파일 구성
spring:
primary-datasource:
jdbc-url: jdbc:mysql://localhost:3306/{DB1}?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
username: {username}
password: {password}
driver-class-name: com.mysql.cj.jdbc.Driver
secondary-datasource:
jdbc-url: jdbc:mysql://localhost:3306/{DB2}?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
username: {username}
password: {password}
driver-class-name: com.mysql.cj.jdbc.Driver
primary-datasource와 secondary-datasource에 대해 각각의 DB 접속 정보를 추가한다.
기존 단일 DB 연결을 위한 datasource 설정 시엔 url로 작성하였으나 다중 DB를 구성할 경우에는 jdbc-url로 변경해서 작성해야 한다. JavaConfig를 통해 사용자가 직접 커스텀 datasource를 구성할 경우 HikariCP가 url이 아닌 jdbc-url을 사용하기 때문이다.
2. DataSource 설정 파일 구성
1) PrimaryConfig
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = "com.example.project.repository",
entityManagerFactoryRef = "primaryEntityManagerFactory",
transactionManagerRef = "primaryTransactionManager"
)
public class PrimaryConfig {
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.primary-datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "primaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
EntityManagerFactoryBuilder builder, @Qualifier("primaryDataSource") DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages("com.example.project.repository")
.persistenceUnit("primary")
.build();
}
@Primary
@Bean(name = "primaryTransactionManager")
public PlatformTransactionManager primaryTransactionManager(
@Qualifier("primaryEntityManagerFactory") EntityManagerFactory primaryEntityManagerFactory) {
return new JpaTransactionManager(primaryEntityManagerFactory);
}
}
@EnableJpaRepositories
는 JPA 리포지토리의 설정을 담당하는 어노테이션이다.- basePackages: JPARepository 인터페이스를 스캔할 패키지 경로
- entityManagerFactoryRef: entityManagerFactory의 빈 이름
- transactionManagerRef: transactionManager의 빈 이름
@Primary
를 통해 스프링이 자동으로 의존성을 주입할 때 우선적으로 선택할 빈을 설정한다. 여기서는 Primary로 지정하는 DB 설정 파일에 해당 어노테이션을 달아준다.
2) SecondaryConfig
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = "com.example.project.repository",
entityManagerFactoryRef = "secondaryEntityManagerFactory",
transactionManagerRef = "secondaryTransactionManager"
)
@RequiredArgsConstructor
public class SecondaryConfig {
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.secondary-datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
EntityManagerFactoryBuilder builder, @Qualifier("secondaryDataSource") DataSource dataSource) {
Map<String, Object> properties = hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
return builder
.dataSource(dataSource)
.packages("com.example.project.repository")
.persistenceUnit("secondary")
.build();
}
@Bean(name = "secondaryTransactionManager")
public PlatformTransactionManager secondaryTransactionManager(
@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory secondaryEntityManagerFactory) {
return new JpaTransactionManager(secondaryEntityManagerFactory);
}
}
@Primary
어노테이션을 제거하는 것을 제외하면 PrimaryConfig와 동일한 방식의 구성이다.
3. 추가 설정
1) Name Staragy
JPA의 기본 설정 상, DB의 테이블이나 필드 이름이 snake_case
로 작성된 경우, camelCase
에서 자동으로 변환해 준다. 하지만 다중 DB를 설정할 경우 해당 기능이 동작하지 않아 따로 설정해주어야 한다.
아래 코드와 같이 jpa, hibernate property 값을 가져와 properties를 설정해 준다.
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = "dac2dac.doctect",
excludeFilters = @ComponentScan.Filter(
type = FilterType.REGEX,
pattern = ".*Mydata.*"),
entityManagerFactoryRef = "primaryEntityManagerFactory",
transactionManagerRef = "primaryTransactionManager"
)
@RequiredArgsConstructor
public class PrimaryConfig {
private final JpaProperties jpaProperties;
private final HibernateProperties hibernateProperties;
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.primary-datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "primaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
EntityManagerFactoryBuilder builder, @Qualifier("primaryDataSource") DataSource dataSource) {
Map<String, Object> properties = hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
return builder
.dataSource(dataSource)
.packages("com.example.project.repository")
.persistenceUnit("primary")
.properties(properties)
.build();
}
@Primary
@Bean(name = "primaryTransactionManager")
public PlatformTransactionManager primaryTransactionManager(
@Qualifier("primaryEntityManagerFactory") EntityManagerFactory primaryEntityManagerFactory) {
return new JpaTransactionManager(primaryEntityManagerFactory);
}
}
2) basePackages
도메인 패키지 구조를 사용하고 있었기 때문에 JPARepositories의 경로를 설정할 때 excludeFilters
와 repositoryImplementationPostfix
와 같은 파라미터를 사용하여 특정 리포지토리 구현체를 포함하거나 제외하였다.
excludeFilters
@EnableJpaRepositories(
basePackages = "dac2dac.doctect",
excludeFilters = @ComponentScan.Filter(
type = FilterType.REGEX,
pattern = ".*Mydata.*")
)
"dac2dac.doctect" 패키지 하위에서 Mydata라는 단어가 들어간 JPARepository 파일명을 제외한 나머지 파일을 스캔 대상으로 한다.
repositoryImplementationPostfix
@EnableJpaRepositories(
basePackages = "dac2dac.doctect.mydata",
repositoryImplementationPostfix = "Mydata"
)
"dac2dac.doctect.mydata" 패키지 하위에서 Mydata라는 접두어가 들어간 JPARepository 파일명만을 스캔 대상으로 한다.
'Framework > Spring' 카테고리의 다른 글
[SpringBoot] @Async로 비동기 처리하기 (0) | 2024.04.18 |
---|---|
[SpringBoot] 외부 API 호출하기(2) (0) | 2024.04.18 |
[SpringBoot] 외부 API 호출하기(1) (2) | 2024.04.18 |
[SpringBoot] MockMvc로 Multipart() 테스트 코드 작성하기 (1) | 2024.02.15 |