Table of Contents
Spring Boot JPA 멀티 데이타소스
목표
두개 이상의 데이타소스를 설정합니다.
application.yml
기존 하나의 데이타소스 설정에서 두개 이상의 데이타소스를 설정할 수 있습니다.
url
설정과 jdbc-url
이 필요합니다.
두개의 데이타소스는 아이피가 달라도 되고, 데이타베이스의 종류가 달라도 됩니다.
spring:
# datasource:
# url: jdbc:sqlserver://XXX.XXX.XXX.XXX;databaseName=db_order
# # url: jdbc:log4jdbc:sqlserver://XXX.XXX.XXX.XXX;databaseName=db_order
# username: -
# password: -
# driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# # driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
datasource:
db-main:
url: jdbc:sqlserver://XXX.XXX.XXX.XXX;databaseName=db_order
jdbc-url: jdbc:sqlserver://XXX.XXX.XXX.XXX;databaseName=db_order
username: -
password: -
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
db-item:
url: jdbc:sqlserver://XXX.XXX.XXX.XXX;databaseName=db_item
jdbc-url: jdbc:sqlserver://XXX.XXX.XXX.XXX;databaseName=db_item
username: -
password: -
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
DataSourceProperties.java
데이타소스를 읽는 설정을 추가합니다.
@Configuration
@EnableConfigurationProperties
public class DataSourceProperties {
@Bean(name = "mainDataSource")
@Qualifier("mainDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.db-main")
public DataSource mainDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Bean(name = "itemDataSource")
@Qualifier("itemDataSource")
@ConfigurationProperties(prefix = "spring.datasource.db-item")
public DataSource itemDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
}
MainDataSourceConfig.java
패키지 기준으로 데이타소스가 할당됩니다.
따라서 Entity/Repository 클래스는 데이타소스별로 분리해서 배치해야 합니다.
중요 데이타소스 쪽에 @Primary
를 붙여줍니다.
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "mainEntityManagerFactory",
transactionManagerRef = "mainTransactionManager",
basePackages = { "kr.pe.skyer9.csapi.domain.db_main" })
public class MainDataSourceConfig {
@Autowired
@Qualifier("mainDataSource")
private DataSource mainDataSource;
@Primary
@Bean(name = "mainEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean mainEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(mainDataSource)
.packages("kr.pe.skyer9.csapi.domain.db_main")
.persistenceUnit("main")
.build();
}
@Primary
@Bean("mainTransactionManager")
public PlatformTransactionManager mainTransactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(mainEntityManagerFactory(builder).getObject());
}
}
itemDataSourceConfig.java
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "itemEntityManagerFactory",
transactionManagerRef = "itemTransactionManager",
basePackages = { "kr.pe.skyer9.csapi.domain.db_item" })
public class itemDataSourceConfig {
@Autowired
@Qualifier("itemDataSource")
private DataSource itemDataSource;
@Bean(name = "itemEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean itemEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(itemDataSource)
.packages("kr.pe.skyer9.csapi.domain.db_item")
.persistenceUnit("item")
.build();
}
@Bean("itemTransactionManager")
public PlatformTransactionManager itemTransactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(itemEntityManagerFactory(builder).getObject());
}
}
Service 레이어
가끔 프로시져 호출 등의 이유로 서비스 레이어에서 EntityManager
를 생성하는 경우가 있습니다.
이런 경우 @RequiredArgsConstructor
를 사용할 수 없고,
@Qualifier("mainEntityManagerFactory")
와 같이 Bean 을 명시해 주어야 정상 작동합니다.
// @RequiredArgsConstructor
@Service
public class OrderMasterService {
private final OrderMasterMapper mapper = Mappers.getMapper(OrderMasterMapper.class);
private final OrderMasterRepository orderMasterRepository;
private final EntityManager entityManager;
public OrderMasterService(OrderMasterRepository orderMasterRepository, @Qualifier("mainEntityManagerFactory") EntityManager entityManager) {
this.orderMasterRepository = orderMasterRepository;
this.entityManager = entityManager;
}
}