Spring Boot + MyBatis에서 멀티 데이터소스를 구성해야 하는 이유

Yu Seong Kim·2025년 12월 11일

SpringBoot

목록 보기
32/33
post-thumbnail

Spring Boot + MyBatis는 단일 데이터소스 환경에서도 훌륭하게 동작하지만,
프로젝트가 커질수록 두 개 이상의 데이터베이스를 동시에 사용해야 하는 상황이 자주 발생합니다.
예를 들어, 메인 비즈니스 데이터 저장용 DB, 로그/사용자/설정 관리용 서브 DB, 외부 시스템 연동 전용 DB등 이런 구조에서는 멀티 데이터소스를 구성해야합니다.

멀티 데이터소스가 왜 필요한가?

  • 데이터 역할 분리
    메인 DB에는 실제 업무 데이터가 저장되고, 서브 DB에는 보조적인 데이터가 저장될 수 있습니다.
    서브 DB가 아닌 다른 DB가 될 수도 있습니다. 예를들면, 사용자 계정 정보, 시스템 설정값, 로그 / 모니터링용 데이터, 공통 코드 / 메타 데이터등 의 데이터를 분리하면 시스템의 안정성과 유지보수성이 크게 향상됩니다.

  • 장애 격리 효과
    서브 DB에 장애가 발생해도 메인 DB의 핵심 로직은 정상 동작합니다.
    “프로젝트 전체 장애” 리스크를 크게 줄이는 효과가 있습니다.

  • 외부 시스템 / 통합 환경에서 필수적인 구조
    외부 회사 API, EC 시스템, 회계 시스템 등과 연동할 때 연동 결과를 저장하는 별도의 DB를 사용하는 경우가 많습니다.

MyBatis에서 멀티 데이터소스 구성방법

구성 요소역할
DataSourceDB 연결을 관리하는 HikariCP
SqlSessionFactoryMyBatis SQL 실행 엔진
SqlSessionTemplateMapper가 사용하는 템플릿
TransactionManager트랜잭션 관리

따라서 DB가 두 개라면 이렇게 구성됩니다.

main  DB → mainDataSource + mainSqlSessionFactory + mainSqlSessionTemplate + mainTransactionManager
sub   DB → subDataSource  + subSqlSessionFactory  + subSqlSessionTemplate  + subTransactionManager

각 Mapper는 어떤 DB를 사용할지 직접 지정해야 하므로
@MapperScan(sqlSessionFactoryRef = …) 설정이 매우 중요합니다.

main DB 구성 예시

@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);
    }
}

sub DB 구성 예시

@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으로 DB를 분리

@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

멀티 데이터소스 판단 기준

아래 중 2개 이상이 존재하면 → 멀티 데이터소스

DataSource 여러 개
SqlSessionFactory 여러 개
SqlSessionTemplate 여러 개
TransactionManager 여러 개
MapperScan이 DB별로 분리됨
Bean 이름이 DB 단위로 구분됨(main, central 등)

profile
1년차 개발자의 Development Record Page

0개의 댓글