다중 DataSource 구성

MyBatis 기반 다중 DataSource @Configuration 등록 패턴 및 트랜잭션 관리

마지막 수정: 2026-06

다중 DataSource 구성

하나의 애플리케이션에서 여러 DB(메인 DB, 이메일 DB, 외부 연동 DB 등)에 독립적으로 접근해야 할 때 DataSource별 @Configuration 클래스를 분리하여 등록한다.


구성 원칙

규칙설명
DataSource별 Config 클래스 분리DataBaseHomeConfig, DataBaseEmailConfig
메인 DataSource에 @Primary 적용Spring이 기본으로 주입할 DataSource 지정
@Qualifier로 비주요 DataSource 지정명시적으로 Bean 이름 지정
SqlSessionFactory 분리DataSource마다 별도 SqlSessionFactory 등록
Mapper 패키지 분리DataSource별 Mapper XML 경로 분리

메인 DataSource 설정 예시

@Configuration
@MapperScan(
    basePackages = "com.{회사명}.{프로젝트명}.home.mapper",
    sqlSessionFactoryRef = "homeSqlSessionFactory"
)
public class DataBaseHomeConfig {

    @Primary
    @Bean(name = "homeDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.home")
    public DataSource homeDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "homeSqlSessionFactory")
    public SqlSessionFactory homeSqlSessionFactory(
            @Qualifier("homeDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setConfigLocation(
            new ClassPathResource("mybatis/mybatis-config.xml"));
        factory.setMapperLocations(
            new PathMatchingResourcePatternResolver()
                .getResources("classpath:mybatis/home/**/mapper/*.xml"));
        return factory.getObject();
    }

    @Primary
    @Bean(name = "homeTransactionManager")
    public DataSourceTransactionManager homeTransactionManager(
            @Qualifier("homeDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

보조 DataSource 설정 예시

@Configuration
@MapperScan(
    basePackages = "com.{회사명}.{프로젝트명}.email.mapper",
    sqlSessionFactoryRef = "emailSqlSessionFactory"
)
public class DataBaseEmailConfig {

    @Bean(name = "emailDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.email")
    public DataSource emailDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "emailSqlSessionFactory")
    public SqlSessionFactory emailSqlSessionFactory(
            @Qualifier("emailDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setMapperLocations(
            new PathMatchingResourcePatternResolver()
                .getResources("classpath:mybatis/email/**/mapper/*.xml"));
        return factory.getObject();
    }

    @Bean(name = "emailTransactionManager")
    public DataSourceTransactionManager emailTransactionManager(
            @Qualifier("emailDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

application.yml 설정

spring:
  datasource:
    home:
      driver-class-name: oracle.jdbc.OracleDriver
      url: ${DB_HOME_URL}
      username: ${DB_HOME_USERNAME}
      password: ${DB_HOME_PASSWORD}
    email:
      driver-class-name: oracle.jdbc.OracleDriver
      url: ${DB_EMAIL_URL}
      username: ${DB_EMAIL_USERNAME}
      password: ${DB_EMAIL_PASSWORD}

@Transactional 사용 시 주의

트랜잭션 매니저가 여러 개이므로 @Transactional에 명시적으로 지정한다.

// 메인 DB (@Primary이므로 생략 가능)
@Transactional(transactionManager = "homeTransactionManager")
public void saveOrder(OrderVo vo) { ... }

// 보조 DB (반드시 명시)
@Transactional(transactionManager = "emailTransactionManager")
public void sendEmail(EmailVo vo) { ... }

디렉터리 구조

src/main/resources/mybatis/
├── mybatis-config.xml          # 공통 MyBatis 설정
├── home/
│   └── mapper/
│       └── UserMapper.xml
└── email/
    └── mapper/
        └── EmailMapper.xml

체크리스트

  • [ ] DataSource별 @Configuration 클래스 분리
  • [ ] 메인 DataSource에 @Primary 적용
  • [ ] @MapperScansqlSessionFactoryRef 명시
  • [ ] Mapper XML 경로를 DataSource별로 분리
  • [ ] @TransactionaltransactionManager 명시 (비주요 DS)
  • [ ] application.yml에 DataSource별 prefix 분리