Spring boot multi datasource ๋ฑ๋ก ์ ์ฃผ์ ์ฌํญ
Spring Boot Multi datasource ๋ฑ๋ก ์ ์ฃผ์ ์ฌํญ
์ต๊ทผ ์งํํ๋ ํ๋ก์ ํธ๋ ์ธ๋ถ ํด๋ฌด์ผ ์ ๋ณด API๋ฅผ ํธ์ถํ์ฌ DB์ ์ ์ฌํ๋ ์๋ฐฐ์น์ฉ Spring Batch ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฐ๋ฐํ๋ ๊ฒ์ด์๋ค.
ํ์ฌ์๋ ์ฌ๋ฌ๊ฐ์ง DataBase๊ฐ ์๋๋ฐ, ๊ทธ ์ค ๋ฉ์ธ DB๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ํ๊ณ , spring batch ์ฉ DB๋ ๋ฐ๋ก ์ฌ์ฉํ๊ฒ ๋์๋ค.
๊ทธ๋์ ๋ฉํฐ datasource bean ์ ๋ฑ๋กํด์ค์ผ ํ๋ค.
๊ทธ ๊ณผ์ ์์ ์ ๋ง ๊ธฐ์ด์ ์ด์ง๋ง ์ค์ํ๋ ๋ถ๋ถ์ ์ค๋ช
ํด๋ณด๊ฒ ๋ค.
Multi Datasource
ํ๋์ ํ๋ก์ ํธ์์ ์ฌ๋ฌ ๊ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฐ๊ฒฐํ๋ ๊ฒ.
spring ์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก yaml ํ์ผ์ ํตํด ์ฝ๊ฒ datasource ๊ตฌ์ฑ์ด ๊ฐ๋ฅํ๋ค.
๋ฐ๋ก java ์ฝ๋๋ก bean ์ ๋ฑ๋กํ ํ์๊ฐ ์์ ๊ฒ์ด๋ค.
ํ์ง๋ง ์ฌ๋ฌ database ๋ฅผ ์ฐ๊ฒฐํ๊ณ ์ ํ๋ค๋ฉด, ์ฐ์ ์์ database ๋ฅผ ์ง์ ํ๊ธฐ ์ํด ์ฝ๋๋ก configuration ์์
์ ์งํํด์ฃผ๋ ๊ฒ์ด ํ์ํ๋ค.
Multi Datasource ์์ ์ฝ๋
@Configuration
@ConditionalOnProperty(
prefix = "~~company.db.units.core-batch",
name = ["enabled"],
havingValue = "true",
matchIfMissing = false
)
@EnableJpaRepositories(
basePackages = ["holiday.batch.infra.db.corebatch"],
entityManagerFactoryRef = CORE_BATCH_ENTITY_MANAGER_FACTORY,
transactionManagerRef = CORE_BATCH_TRANSACTION_MANAGER,
)
class CoreBatchDatabaseConfiguration : DatabaseConfigurationBase("core-batch") {
@Bean(CORE_BATCH_DATA_SOURCE)
@ConfigurationProperties(
DatabaseUnitProperties.PROP_BINDING_PREFIX + "core-batch" + DatabaseUnitProperties.PROP_BINDING_SUFFIX_HIKARI
)
fun coreBatchDataSource(): DataSource = super.dataSource()
@Bean(CORE_BATCH_ENTITY_MANAGER_FACTORY)
fun coreBatchEntityManagerFactory(
@Qualifier(CORE_BATCH_DATA_SOURCE) dataSource: DataSource
): LocalContainerEntityManagerFactoryBean = super.entityManagerFactory(dataSource)
@Bean(CORE_BATCH_TRANSACTION_MANAGER)
fun coreBatchTransactionManager(
@Qualifier(CORE_BATCH_DATA_SOURCE) dataSource: DataSource,
): PlatformTransactionManager = JdbcTransactionManager(dataSource)
}
core-batch - spring batch ํ
์ด๋ธ์ ์ํ db ์ด๋ค.
์ด๋ฅผ ์ํ configuration ์์
์ด๋ค.
@Configuration
@ConditionalOnProperty(
prefix = "~~conmpany.db.units.main",
name = ["enabled"],
havingValue = "true",
matchIfMissing = false
)
@EnableJpaRepositories(
basePackages = ["holiday.batch.infra.db.main"],
entityManagerFactoryRef = MAIN_ENTITY_MANAGER_FACTORY,
transactionManagerRef = MAIN_JPA_TRANSACTION_MANAGER,
)
class MainDatabaseConfiguration : DatabaseConfigurationBase("main") {
@Bean(MAIN_DATA_SOURCE)
@ConfigurationProperties(
DatabaseUnitProperties.PROP_BINDING_PREFIX + "main" + DatabaseUnitProperties.PROP_BINDING_SUFFIX_HIKARI
)
fun mainDataSource(): DataSource = super.dataSource()
@Bean(MAIN_ENTITY_MANAGER_FACTORY)
fun mainEntityManagerFactory(): LocalContainerEntityManagerFactoryBean =
super.entityManagerFactory(mainDataSource())
@Bean(MAIN_JPA_TRANSACTION_MANAGER)
fun mainTransactionManager(
@Qualifier(MAIN_ENTITY_MANAGER_FACTORY) emf: EntityManagerFactory
): PlatformTransactionManager =
super.transactionManager(mainDataSource(), emf)
@Bean(MAIN_JDBC_TRANSACTION_MANAGER)
fun mainJdbcTransactionManager(): PlatformTransactionManager {
return JdbcTransactionManager(mainDataSource())
}
}
main - main database ๋ฅผ ์ํ configuration ์์ ์ด๋ค.
@Configuration
@ComponentScan(basePackageClasses = [DatabaseAutoConfiguration::class])
@EnableConfigurationProperties(value = [DatabaseProperties::class])
@EnableJpaAuditing
class DatabaseAutoConfiguration
object DataBaseConstants {
const val MAIN_DATA_SOURCE = "mainDataSource"
const val MAIN_ENTITY_MANAGER_FACTORY = "mainEntityManagerFactory"
const val MAIN_JPA_TRANSACTION_MANAGER = "mainJpaTransactionManager"
const val MAIN_JDBC_TRANSACTION_MANAGER = "mainJdbcTransactionManager"
const val CORE_BATCH_DATA_SOURCE = "coreBatchDataSource"
const val CORE_BATCH_ENTITY_MANAGER_FACTORY = "coreBatchEntityManagerFactory"
const val CORE_BATCH_TRANSACTION_MANAGER = "coreBatchTransactionManager"
}
ํ์ฌ ํ๋ก์ ํธ ๊ตฌ์กฐ๋ ๋ฉํฐ ๋ชจ๋ ํํ๋ก ๊ตฌ์ฑ ๋์ด ์๊ธฐ ๋๋ฌธ์, auto-configuration ์ ์ํด component scan ์ ์งํํด์ฃผ์๋ค.
๋ฌธ์ ์ ์ด ๋ณด์ด์ญ๋๊น?
์์ datasource ๊ตฌ์ฑ ์์ ์ ๋ฌธ์ ์ ์ด ๋์ ๋ค์ด์ค๋๊ฐ?
์ ์ค์ ํ์ผ์ ๊ฐ์ง๊ณ application ์ ์คํํ๋ค๋ฉด required a single bean, but (n) were found
๋๊ฐ ์ด๋ฐ ์์ธ ๋ฉ์์ง๊ฐ ๋ฐ์ํ๋ฉฐ ์ข
๋ฃ๋ ๊ฒ์ด๋ค.
๋น์ฐํ bean ์ด๋ฆ์ ๋ค๋ฅด๊ฒ ํ๋๋ฐ, ๋ฌด์์ด ๋ฌธ์ ์ผ๊น ํ ๊ฒ์ด๋ค.
ํ์ง๋ง ์ด๋ ์ด๋ฆฌ์์ ์ฐฉ๊ฐ์ด๋ค.
์ด datasource ์ค์ ์ผ๋ก๋,
spring boot ๋ ์ด๋ค Datasource ๋ฅผ ๋ฉ์ธ์ผ๋ก ์ฌ์ฉํ ์ง ๋ชจ๋ฅธ๋ค.
core-batch ๊ฐ ๋ฉ์ธ์ธ์ง, main ์ด ๋ฉ์ธ์ธ์ง.. ๋ชจ๋ฅด๋ ๊ฒ์ด๋ค.
์ฐธ ๋น์ฐํ ๊ฒ์ด๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ
๋ฌธ์ ํด๊ฒฐ์ ์ํด ์ด๋ค datasource ๊ฐ ๋ฉ์ธ์ธ์ง spring boot ์๊ฒ ์๋ ค์ฃผ์ด์ผ ํ๋ค.
์๋ฌด๋๋ spring batch ์ ํ๋ฆฌ์ผ์ด์
์ด๊ธฐ ๋๋ฌธ์, batch ์ฉ db ๊ฐ ๋ฉ์ธ์ด ๋์ด์ผ ๋์ง ์ถ๋ค.
๊ทธ๋์ @Primary ์ ๋ ธํ ์ด์ ์ ๋ถ์ฌ์ฃผ์ด ์ด๊ฑธ ๋ฉ์ธ์ผ๋ก ์ฌ์ฉํ๋ผ ์๋ ค์ฃผ์๋ค.
@Configuration
@ConditionalOnProperty(
prefix = "~~company.db.units.core-batch",
name = ["enabled"],
havingValue = "true",
matchIfMissing = false
)
@EnableJpaRepositories(
basePackages = ["holiday.batch.infra.db.corebatch"],
entityManagerFactoryRef = CORE_BATCH_ENTITY_MANAGER_FACTORY,
transactionManagerRef = CORE_BATCH_TRANSACTION_MANAGER,
)
class CoreBatchDatabaseConfiguration : DatabaseConfigurationBase("core-batch") {
@Primary
@Bean(CORE_BATCH_DATA_SOURCE)
@ConfigurationProperties(
DatabaseUnitProperties.PROP_BINDING_PREFIX + "core-batch" + DatabaseUnitProperties.PROP_BINDING_SUFFIX_HIKARI
)
fun coreBatchDataSource(): DataSource = super.dataSource()
@Primary
@Bean(CORE_BATCH_ENTITY_MANAGER_FACTORY)
fun coreBatchEntityManagerFactory(
@Qualifier(CORE_BATCH_DATA_SOURCE) dataSource: DataSource
): LocalContainerEntityManagerFactoryBean = super.entityManagerFactory(dataSource)
@Primary
@Bean(CORE_BATCH_TRANSACTION_MANAGER)
fun coreBatchTransactionManager(
@Qualifier(CORE_BATCH_DATA_SOURCE) dataSource: DataSource,
): PlatformTransactionManager = JdbcTransactionManager(dataSource)
}
์ด๋ ๊ฒ ํ๋ฉด ์ ์์ ์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํ ๋๊ณ batch ๊น์ง ์ ์์ ์ผ๋ก ์คํํ๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค.
๊ฒฐ๋ก
๊ธฐ์กด์ @Primary ์ ๋
ธํ
์ด์
์ ์ฌ์ฉํ๋ฉด์ ๊ฐ๋ฐํ ์ผ์ด ์์์ด์, ์ด๊ฑธ ์ ๋ฌ์์ค์ผ ํ๋์ง ๋ชฐ๋์๋ค.
multi datasource ๊ตฌ์ฑ์ ํ ์ผ์ด ์์๊ธฐ๋ ํ๊ณ .
ํ์ง๋ง ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ด๊ณ ๋ ๋น์ฐํ bean ๋ฑ๋ก์ ๋ํ
์ผ์ ๋์ณค๋ค๋ ์๊ฐ์ ์ญ์ ๊ธฐ๋ณธ์ด ์ค์ํ๋ค๋ผ๋ ์๊ฐ์ ํด๋ณธ๋ค.
Primary. ์ ์๊ณ ์ ์ฌ์ฉํด๋ณด์.