
Spring Boot + MyBatis는 단일 데이터소스 환경에서도 훌륭하게 동작하지만,
프로젝트가 커질수록 두 개 이상의 데이터베이스를 동시에 사용해야 하는 상황이 자주 발생합니다.
예를 들어, 메인 비즈니스 데이터 저장용 DB, 로그/사용자/설정 관리용 서브 DB, 외부 시스템 연동 전용 DB등 이런 구조에서는 멀티 데이터소스를 구성해야합니다.
데이터 역할 분리
메인 DB에는 실제 업무 데이터가 저장되고, 서브 DB에는 보조적인 데이터가 저장될 수 있습니다.
서브 DB가 아닌 다른 DB가 될 수도 있습니다. 예를들면, 사용자 계정 정보, 시스템 설정값, 로그 / 모니터링용 데이터, 공통 코드 / 메타 데이터등 의 데이터를 분리하면 시스템의 안정성과 유지보수성이 크게 향상됩니다.
장애 격리 효과
서브 DB에 장애가 발생해도 메인 DB의 핵심 로직은 정상 동작합니다.
“프로젝트 전체 장애” 리스크를 크게 줄이는 효과가 있습니다.
외부 시스템 / 통합 환경에서 필수적인 구조
외부 회사 API, EC 시스템, 회계 시스템 등과 연동할 때 연동 결과를 저장하는 별도의 DB를 사용하는 경우가 많습니다.
| 구성 요소 | 역할 |
|---|---|
| DataSource | DB 연결을 관리하는 HikariCP |
| SqlSessionFactory | MyBatis SQL 실행 엔진 |
| SqlSessionTemplate | Mapper가 사용하는 템플릿 |
| TransactionManager | 트랜잭션 관리 |
따라서 DB가 두 개라면 이렇게 구성됩니다.
main DB → mainDataSource + mainSqlSessionFactory + mainSqlSessionTemplate + mainTransactionManager
sub DB → subDataSource + subSqlSessionFactory + subSqlSessionTemplate + subTransactionManager
각 Mapper는 어떤 DB를 사용할지 직접 지정해야 하므로
@MapperScan(sqlSessionFactoryRef = …) 설정이 매우 중요합니다.
@Configuration
@EnableTransactionManagement
@MapperScan(
basePackages = "com.example.project.mapper.main",
sqlSessionFactoryRef = "mainSqlSessionFactory"
)
public class MainDataSourceConfig {
@Primary
@Bean(name = "mainDataSource")
@ConfigurationProperties(prefix = "spring.datasource.main.hikari")
public DataSource mainDataSource() {
return DataSourceBuilder.create()
.type(HikariDataSource.class)
.build();
}
@Bean(name = "mainSqlSessionFactory")
public SqlSessionFactory mainSqlSessionFactory(
@Qualifier("mainDataSource") DataSource mainDataSource,
ApplicationContext applicationContext
) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(mainDataSource);
factory.setMapperLocations(
applicationContext.getResources("classpath:mapper/main/**/*.xml")
);
return factory.getObject();
}
@Bean(name = "mainSqlSessionTemplate")
public SqlSessionTemplate mainSqlSessionTemplate(
@Qualifier("mainSqlSessionFactory") SqlSessionFactory mainSqlSessionFactory
) {
return new SqlSessionTemplate(mainSqlSessionFactory);
}
@Bean(name = "mainTransactionManager")
public DataSourceTransactionManager mainTransactionManager(
@Qualifier("mainDataSource") DataSource mainDataSource
) {
return new DataSourceTransactionManager(mainDataSource);
}
}
@Configuration
@MapperScan(
basePackages = "com.example.project.mapper.sub",
sqlSessionFactoryRef = "subSqlSessionFactory"
)
public class SubDataSourceConfig {
@Bean(name = "subDataSource")
@ConfigurationProperties(prefix = "spring.datasource.sub.hikari")
public DataSource subDataSource() {
return DataSourceBuilder.create()
.type(HikariDataSource.class)
.build();
}
@Bean(name = "subSqlSessionFactory")
public SqlSessionFactory subSqlSessionFactory(
@Qualifier("subDataSource") DataSource subDataSource,
ApplicationContext applicationContext
) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(subDataSource);
factory.setMapperLocations(
applicationContext.getResources("classpath:mapper/sub/**/*.xml")
);
return factory.getObject();
}
@Bean(name = "subSqlSessionTemplate")
public SqlSessionTemplate subSqlSessionTemplate(
@Qualifier("subSqlSessionFactory") SqlSessionFactory subSqlSessionFactory
) {
return new SqlSessionTemplate(subSqlSessionFactory);
}
@Bean(name = "subTransactionManager")
public DataSourceTransactionManager subTransactionManager(
@Qualifier("subDataSource") DataSource subDataSource
) {
return new DataSourceTransactionManager(subDataSource);
}
}
@MapperScan(
basePackages = "com.example.project.mapper.main",
sqlSessionFactoryRef = "mainSqlSessionFactory"
)
→ main Mapper는 main DB로만 연결
→ sub Mapper는 sub DB로만 연결
이 규칙이 MyBatis 멀티 데이터소스의 핵심입니다.
단일 DB는 구성 요소가 단 1세트만 존재합니다.
DataSource 1개
SqlSessionFactory 1개
SqlSessionTemplate 1개
TransactionManager 1개
MapperScan 1개
┌───────────────┐
│ DataSource #1
└───────┬───────┘
│
┌─────────▼────────┐
│ SqlSessionFactory
└─────────┬────────┘
│
┌─────────▼────────┐
│ SqlSessionTemplate
└─────────┬────────┘
│
Mapper Package A
────────────────────────────────────────────
┌───────────────┐
│ DataSource #2
└───────┬───────┘
│
┌─────────▼────────┐
│ SqlSessionFactory
└─────────┬────────┘
│
┌─────────▼────────┐
│ SqlSessionTemplate
└─────────┬────────┘
│
Mapper Package B
DataSource 여러 개
SqlSessionFactory 여러 개
SqlSessionTemplate 여러 개
TransactionManager 여러 개
MapperScan이 DB별로 분리됨
Bean 이름이 DB 단위로 구분됨(main, central 등)