Spring Boot + MyBatis로 두 개의 데이터소스 쓰기
Primary/Secondary 두 DataSource를 분리하고 MapperScan으로 패키지별로 매핑
Spring Boot + MyBatis로 두 개의 데이터소스 쓰기
여러 DB를 한 애플리케이션에서 다룰 때, MyBatis의 MapperScan을 패키지 단위로 나누고 각 패키지에 별도 SqlSessionFactory를 매핑한다.
yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
spring:
datasource:
hikari:
primary:
driver-class-name: org.h2.Driver
jdbc-url: jdbc:h2:file:./build/h2db/db/primary;DB_CLOSE_DELAY=-1
username: primary_user
password:
secondary:
driver-class-name: org.h2.Driver
jdbc-url: jdbc:h2:file:./build/h2db/db/secondary;DB_CLOSE_DELAY=-1
username: secondary_user
password:
Primary DataSource
@Primary가 붙은 빈이 기본 주입 대상이 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Configuration
@EnableTransactionManagement
@MapperScan(value = "com.test.dao.primary", sqlSessionFactoryRef = "primarySqlSessionFactory")
public class PrimaryDatasourceConfiguration {
@Bean @Primary
@ConfigurationProperties("spring.datasource.hikari.primary")
public HikariConfig primaryHikariConfig() {
return new HikariConfig();
}
@Bean @Primary
public DataSource primaryDataSource() {
return new HikariDataSource(primaryHikariConfig());
}
@Bean(name = "primarySqlSessionFactory") @Primary
public SqlSessionFactory sqlSessionFactory(
@Qualifier("primaryDataSource") DataSource dataSource,
ApplicationContext applicationContext) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setMapperLocations(applicationContext.getResources("classpath:mapper/primary/*.xml"));
factory.setTypeAliasesPackage("com.test.service.dto");
return factory.getObject();
}
@Bean(name = "primarySqlSessionTemplate") @Primary
public SqlSessionTemplate sqlSessionTemplate(
@Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
Secondary DataSource
@Primary만 빠진 같은 구조.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Configuration
@EnableTransactionManagement
@MapperScan(value = "com.test.dao.secondary", sqlSessionFactoryRef = "secondarySqlSessionFactory")
public class SecondaryDatasourceConfiguration {
@Bean
@ConfigurationProperties("spring.datasource.hikari.secondary")
public HikariConfig secondaryHikariConfig() {
return new HikariConfig();
}
@Bean
public DataSource secondaryDataSource() {
return new HikariDataSource(secondaryHikariConfig());
}
@Bean(name = "secondarySqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(
@Qualifier("secondaryDataSource") DataSource dataSource,
ApplicationContext applicationContext) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setMapperLocations(applicationContext.getResources("classpath:mapper/secondary/*.xml"));
factory.setTypeAliasesPackage("com.test.service.dto");
return factory.getObject();
}
@Bean(name = "secondarySqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(
@Qualifier("secondarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
패키지 분리 규칙
- DAO/Mapper 인터페이스는
com.test.dao.primary,com.test.dao.secondary로 분리 - XML mapper도
classpath:mapper/primary/*.xml,classpath:mapper/secondary/*.xml로 분리 - 트랜잭션은 보통 Primary 기준. Secondary 쪽에 별도 트랜잭션이 필요하면
@Transactional("secondaryTransactionManager")로 명시 주입
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.