대부분의 프로젝트에서는 하나의 데이터베이스만 사용하지만,
읽기/쓰기 분리(Master/Slave) 또는 비즈니스별로 다른 DB를 사용할 필요가 있는 상황도 종종 발생합니다.
이 글에서는 Spring Boot에서 MyBatis로 다중 데이터베이스를 설정하는 방법을
실제 실무 환경에 맞춰 Master / Slave 구조를 기준으로 상세히 정리해봅니다.
사용 환경 예시
- Spring Boot 3.x
- MyBatis-Spring-Boot-Starter
- MySQL 또는 MariaDB
- Maven
기본 디렉토리 구조
src/
├── main/
│ ├── java/
│ │ └── com/example/
│ │ ├── config/ ← DB 설정 클래스
│ │ └── mapper/
│ │ ├── master/ ← Master Mapper
│ │ └── slave/ ← Slave Mapper
│ └── resources/
│ └── mapper/
│ ├── master/ ← Master XML
│ └── slave/ ← Slave XML
1. application.yml 설정
spring:
datasource:
master:
url: jdbc:mysql://localhost:3306/master_db
username: root
password: root123
driver-class-name: com.mysql.cj.jdbc.Driver
slave:
url: jdbc:mysql://localhost:3306/slave_db
username: root
password: root123
driver-class-name: com.mysql.cj.jdbc.Driver
2. Master DB 설정 클래스
@Configuration
@Primary
@MapperScan(basePackages = "com.example.mapper.master", sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDBConfig {
@Bean(name = "masterDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "masterSqlSessionFactory")
@Primary
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource ds, ApplicationContext ctx) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(ds);
factory.setMapperLocations(ctx.getResources("classpath:mapper/master/**/*.xml"));
return factory.getObject();
}
@Bean(name = "masterSqlSessionTemplate")
@Primary
public SqlSessionTemplate masterSqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sf) {
return new SqlSessionTemplate(sf);
}
}
3. Slave DB 설정 클래스
@Configuration
@MapperScan(basePackages = "com.example.mapper.slave", sqlSessionFactoryRef = "slaveSqlSessionFactory")
public class SlaveDBConfig {
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "slaveSqlSessionFactory")
public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource ds, ApplicationContext ctx) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(ds);
factory.setMapperLocations(ctx.getResources("classpath:mapper/slave/**/*.xml"));
return factory.getObject();
}
@Bean(name = "slaveSqlSessionTemplate")
public SqlSessionTemplate slaveSqlSessionTemplate(@Qualifier("slaveSqlSessionFactory") SqlSessionFactory sf) {
return new SqlSessionTemplate(sf);
}
}
4. Mapper 분리 예시
Master Mapper
package com.example.mapper.master;
@Mapper
public interface UserMapper {
void insertUser(User user);
}
Slave Mapper
package com.example.mapper.slave;
@Mapper
public interface UserReadMapper {
User selectUserById(Long id);
}
XML 파일은 resources/mapper/master/, resources/mapper/slave/ 디렉토리에 배치
5. Transaction 설정 (선택)
각 DB에 대해 트랜잭션 설정이 필요하다면 아래처럼 구성합니다:
@Bean(name = "masterTransactionManager")
@Primary
public DataSourceTransactionManager masterTransactionManager(@Qualifier("masterDataSource") DataSource ds) {
return new DataSourceTransactionManager(ds);
}
@Bean(name = "slaveTransactionManager")
public DataSourceTransactionManager slaveTransactionManager(@Qualifier("slaveDataSource") DataSource ds) {
return new DataSourceTransactionManager(ds);
}
실무 팁
- @Primary는 기본 DB 설정으로 지정할 때 꼭 필요합니다.
- @MapperScan에 sqlSessionFactoryRef를 정확히 지정해야 연결이 꼬이지 않습니다.
- application.yml에서 spring.datasource.master/slave 설정을 각각 분리해야 합니다.
- 커스텀 쿼리는 XML 파일을 master/ 또는 slave/ 디렉토리에 명확히 분리해 주세요.
자주 묻는 질문
Q. JPA랑 같이 써도 되나요?
가능합니다. 단, MyBatis와 JPA의 트랜잭션 관리 방식이 다르기 때문에 @Transactional
적용 범위를 명확히 해야 합니다.
Q. 여러 Slave를 동적으로 로드밸런싱 할 수 있나요?
기본 MyBatis만으로는 어렵지만, Spring Cloud + RoutingDataSource 또는 ShardingSphere 같은 프레임워크를 쓰면 가능합니다.
마무리
MyBatis 기반 프로젝트에서 Master/Slave DB 분리는 트래픽 최적화와 장애 분산을 위해 꼭 필요한 구조입니다.
Spring Boot에서는 다중 DB 설정을 분리하고 @MapperScan
과 SqlSessionFactory
를 명확히 설정하면
생각보다 매우 쉽게 다중 DB 환경을 구축할 수 있습니다.
댓글