본 포스팅은 프로젝트 완료 후, To do로 남겨둔 회원 탈퇴 이관과 관련한 작업을 위해서 다중 데이터베이스 연결과 관련된 포스팅으로 실제 회원 탈퇴와 관련된 정책은 회사마다 다르므로 실제 이관 작업은 생략하고, 다중 데이터베이스를 연결하는 것에 초점을 맞췄습니다.
스프링 부트에서는 하나의 데이터베이스에 대해서만 application.properties 변수 설정을 통해 연결이 가능하기 때문에 2개 이상부터는 Config 클래스 작성을 통해서만 연결이 가능합니다.
단순히 application.properties 파일에 2개의 DB 소스를 줄 경우 오류가 발생하고, Config 클래스를 통해 이를 해결해야 합니다.
(이번 포스팅에서는 MY SQL의 데이터베이스 2개를 통해 실습을 진행합니다.)
MYSQL은 내부에 독립적인 DB공간을 제공하기 때문에 내부에 DB 2개를 생성하여 진행합니다.

각각의 데이터베이스에 해당하는 Entity와 repository를 담을 패키지를 생성합니다.
연결할 데이터베이스의 개수 만큼 Config 클래스를 작성하면 됩니다.
package com.example.testdatabase.config;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.testdatabase.firstdb.repository",
entityManagerFactoryRef = "firstEntityManger",
transactionManagerRef = "firstTransactionManager"
)
public class FirstDatabaseConfig {
@Primary
@Bean
public PlatformTransactionManager firstTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(firstEntityManger().getObject());
return transactionManager;
}
@Primary
@Bean
public LocalContainerEntityManagerFactoryBean firstEntityManger() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(firstDataSource());
em.setPackagesToScan(new String[]{"com.example.testdatabase.firstdb.entity"});
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
em.setJpaPropertyMap(properties);
return em;
}
@Primary
@Bean
public DataSource firstDataSource() {
return DataSourceBuilder.create()
.driverClassName("com.mysql.cj.jdbc.Driver")
.url("jdbc:mysql://아이피:3306/디비?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true")
.username("")
.password("")
.build();
}
}
코드와 관련된 설명을 잠깐 해보자면,
일단 @Configuration으로 설정파일임을 명시하고,
@EnableJpaRepositories를 통해 JpaRepository를 활성화 합니다.
@EnableJpaRepositories의
즉, 각 데이터 소스에 대한 EntityManagerFactory와PlatformTransactionManager를 직접 설정해주어야 하는 것입니다.
직접 설정한 firstEntityManger()를 보면
em.setDataSource(firstDataSource()); //데이터 소스 set
em.setPackagesToScan(new String[]{"com.example.testdatabase.firstdb.entity"}); // entity를 스캔할 패키지를 설정합니다. 이것은 string 배열 값으로 들어갑니다.
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); // 어댑터 설정
//ddl autp 설정을 map에 넣어서 entitiymanger의 jpapropertymap의 넣어줍니다.
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
em.setJpaPropertyMap(properties);
이렇게 됩니다.
그 다음 firstTransactionManager()를 보면
paTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(firstEntityManger().getObject()); //위에서 설정한 entitymanger값을 넣어줍니다.
return transactionManager;
다음 firstDataSource()를 보면
@Primary
@Bean
public DataSource firstDataSource() {
//builder패턴을 통해 datasource를 만들어 관련된 설정값들을 지정해 줍니다.
return DataSourceBuilder.create()
.driverClassName("com.mysql.cj.jdbc.Driver")
.url("jdbc:mysql://아이피:3306/디비?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true")
.username("")
.password("")
.build();
}
여기서 실행을 시키면 오류가 납니다.
second의 config와는 다르게 first에는 오류가 나지 않기 위해 @Primary 어노테이션을 각각의 빈에 적어줍니다.
package com.example.testdatabase.config;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.testdatabase.seconddb.repository",
entityManagerFactoryRef = "secondEntityManager",
transactionManagerRef = "secondTransactionManager"
)
public class SecondDatabaseConfig {
@Bean
public PlatformTransactionManager secondTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(secondEntityManager().getObject());
return transactionManager;
}
@Bean
public LocalContainerEntityManagerFactoryBean secondEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(secondDataSource());
em.setPackagesToScan(new String[]{"com.example.testdatabase.seconddb.entity"});
em.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
em.setJpaPropertyMap(properties);
return em;
}
@Bean
public DataSource secondDataSource() {
return DataSourceBuilder.create()
.driverClassName("com.mysql.cj.jdbc.Driver")
.url("jdbc:mysql://아이피:3306/디비?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true")
.username("")
.password("")
.build();
}
}
second 또한 first config와 동일한 코드이므로 설명은 생략합니다.