Backend/Spring

[Spring boot] 다중 데이터베이스 연결

나는 유찌 2020. 3. 14. 10:54

회사에서 문서 작업을 하며 mybatis에서 다중 데이터베이스 연결을 시도했다.

전 프로젝트를 진행하면서 JPA를 이용해서도 연결을 했었는데 그건 나중에 포스팅 하도록 하겠다.

 

 

 


 

 

 

1. 프로젝트 구조

 

config 폴더는 모든 설정을 관리하는 폴더입니다.

'OneDataSourcrConfig'는 첫번째 데이터베이스 연결에 관한 설정이고,

'TwoDataSourceConfig'는 두번째 데이터베이스입니다.

 

 

각각 데이터베이스에 대한 Controller, Service, DAO, Domain은 폴더를 만들어 관리합니다.

간단하게 'test1', 'test2'로 설정했습니다.

 

 

가장 중요한 점은 Config 폴더의 위치입니다.

Config에는 Domain, Mapper.xml 폴더 경로를 입력하는 코드가 있기 때문에

이를 스캔하기 위해 Config 폴더와 test1, test2 폴더는 동일 폴더 아래 존재해야 합니다.

 

 

 

2. dependency 추가

 

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>

</dependency>


<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>

</dependency>

 

 

본인은 Maven을 사용했으므로 프로젝트의 pom.xml 파일을 열고 Mybatis, 사용 DB dependency를 추가합니다.

* 본인은 Mysql을 이용했습니다.

 

 

 

3. 'application.properties'

 

resources 밑의 application.properties에 들어가 DB 정보를 입력합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
## test1
spring.datasource.test1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.test1.jdbc-url=jdbc:mysql://localhost:3306/test1?serverTimezone=UTC
spring.datasource.test1.username=root
spring.datasource.test1.password=1234
 
## test2
spring.datasource.test2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.test2.jdbc-url=jdbc:mysql://localhost:3306/test2?serverTimezone=UTC
spring.datasource.test2.username=root
spring.datasource.test2.password=1234
 
 

 

test1의 이름은 공통적으로 'spring.datasource.test1.~'으로 시작하고

test2의 이름은 공통적으로 'spring.datasource.test2.~'으로 시작하는 것에 유의합니다.

 

config 파일에서 해당 내용을 통해 설정합니다.

 

 

 

4. Config 작성

 

 

1) 첫번째 (test1) DB

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
@Configuration
@MapperScan(value = "com.example.demo.test1.repository", sqlSessionFactoryRef = "factory")
public class OneDataSourceConfig {
 
    @Primary
    @Bean(name = "datasource")
    @ConfigurationProperties(prefix = "spring.datasource.test1")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Primary
    @Bean(name = "factory")
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(dataSource);
        sqlSessionFactory.setTypeAliasesPackage("com.example.demo.test1");
        sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper1/*.xml"));
        return sqlSessionFactory.getObject();
    }
    
    @Primary
    @Bean(name = "sqlSession")
    public SqlSessionTemplate sqlSession(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
 
 

사용할 Bean을 생성합니다.

 

'Primary'라는 어노테이션은 Bean을 생성 시 우선권을 주겠다는 의미입니다.

없으면 'TwoDataSourceConfig' 파일 중 한 곳에는 이를 설정하라는 오류가 나오니 꼭 입력해야 합니다.

 

긱 'Bean'의 이름을 지정해주는데 'TwoDataSourceConfig'의 Bean 이름과 동일하면 충돌하니 다르게 입력합니다.

 

'ConfigurationProperties' 어노테이션의 perfix는 위의 application.properties에 입력해 놓은 DB 정보 중

어떤 것을 쓰겠다고 알려주는 역할입니다.

 

'spring.datasource.test1.~'이였던 점을 유의하여 입력합니다!

 

 

2) 두번째 (test2) DB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
@MapperScan(value = "com.example.demo.test2.repository", sqlSessionFactoryRef = "factory2")
public class TwoDataSourceConfig {
 
    @Bean(name = "datasource2")
    @ConfigurationProperties(prefix = "spring.datasource.test2")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean(name = "factory2")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("datasource2") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(dataSource);
        sqlSessionFactory.setTypeAliasesPackage("com.example.demo.test2");
        sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper2/*.xml"));
        return sqlSessionFactory.getObject();
    }
    
    @Bean(name = "sqlSession2")
    public SqlSessionTemplate sqlSession(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
 

두번째 데이터베이스를 설정합니다.

 

Bean의 이름이 위와 동일하지 않은 것과 ConfigurationProperties에서 'spring.datasource.test2'라고 설정해 놓은 것을 주의합니다.

 

 

 

5. TEST

 

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
34
35
36
37
38
39
40
41
42
@SpringBootApplication
public class MultipleDataSourceApplication implements CommandLineRunner {
 
    @Autowired
    @Resource(name = "datasource")
    private DataSource datasource1;
 
    @Autowired
    @Resource(name = "datasource2")
    private DataSource datasource2;
 
    @Autowired
    JdbcTemplate template;
 
    public static void main(String[] args) {
        SpringApplication.run(MultipleDataSourceApplication.class, args);
    }
 
    @Override
    public void run(String... args) throws Exception {
        // TODO Auto-generated method stub
        try (Connection connection = datasource1.getConnection()) {
            System.out.println(connection.getMetaData().getURL());
 
            Statement statement = connection.createStatement();
 
            String sql = "CREATE TABLE TEST1(age INTEGER, name VARCHAR(255))";
           statement.execute(sql);
 
        }
 
        try (Connection connection = datasource2.getConnection()) {
            System.out.println(connection.getMetaData().getURL());
 
            Statement statement = connection.createStatement();
 
            String sql = "CREATE TABLE TEST2(age INTEGER, name VARCHAR(255))";
           statement.execute(sql);
        }
    }
 
}
 

Resource 어노테이션은 생성한 datasource의 bean 이름을 통해 호출하고자 하는 datasource를 지정해 주는 것입니다.

 

 

코드는 간단하게 실행 시 Console에 연결된 DB 정보를 출력하고,

연결된 DB에 각 TEST1, TEST2라는 테이블을 생성하는 쿼리를 실행하는 코드입니다.

 

 

boot 프로젝트를 실행시켜주고 Mysql 워크벤치에 들어가서 확인을 해보면

 

이렇게 각 설정한 스키마 test1, test2에 테이블이 생성된 것을 확인할 수 있습니다.  : )