티스토리 뷰
[SpringBoot JPA] 다중 DB 설정하기 (multi Datasource + 이기종 DB)
종벌🍀 2023. 10. 19. 17:27
간혹 사이트들을 연계해야 할때,
그 중에서도 api 없는 사이트의 데이터를 사용해야할 때,
하나의 웹에서 여러 DB를 연결 시켜 사용해야 할 때가 있다.
간단하게 DB Link 로 해결하려 했으나 메인으로 쓰는 DB와 타 사이트 DB가 달라서
복잡쿼리를 쓸때 제약이 쫌 발생해서 DB를 하나 더 연결하기로 했다.
SpringBoot 는 Database 연결을 자동으로 해주기 때문에
다중 DB를 연결하려면 설정부를 재작성해줘야 한다.
일단 db 연동 정보를 추가해준다.
spring:
datasource:
driver-class-name: org.mariadb.jdbc.Driver
jdbc-url: jdbc:mariadb://localhost:3306/jpa
username: root
password: ****
second-datasource:
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc-url: jdbc:sqlserver://localhost:1433;database=sample
username: local
password: ****
기존 url 이라고 작성했던 부분을 jdbc-url 로 변경한다.
그리고 datasource 이름을 다르게 구분되도록 변경한다.
(driver-class-name은 작성안해도 url 보고 알아서 설정된다.)
이제 자동으로 연결되던 설정을 java코드로 재설정해준다.
이때 primary DB와 subDB 설정 2개를 해줘야 한다.
그리고 주 DB에 @primary 어노테이션을 지정해야 한다.
그렇지 않으면 bean 이 1개 이상이라고 에러가 발생한다.
그리고 @EnableJpaRepositories 로 Jpa 가 사용될 위치를 지정해준다.
@Configuration
@EnableJpaRepositories(
basePackages = "com.sample.core.maria",
entityManagerFactoryRef = "primaryEntityManager",
transactionManagerRef = "primaryTransactionManager"
)
public class PrimaryConfig {
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean primaryEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(primaryDataSource());
em.setPackagesToScan(new String[] {"com.sample.core.maria.test"});
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
vendorAdapter.setGenerateDdl(true);
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> prop = new HashMap<>();
prop.put("hibernate.dialect", "org.hibernate.dialect.MariaDBDialect");
prop.put("hibernate.hbm2ddl.auto", "update");
prop.put("hibernate.format_sql", true);
em.setJpaPropertyMap(prop);
return em;
}
@Bean
@Primary
public PlatformTransactionManager primaryTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(primaryEntityManager().getObject());
return transactionManager;
}
}
두번째 DB도 작성해주는데 @primary 없애는 것을 잊지 말자
@Configuration
@EnableJpaRepositories(
basePackages = "com.sample.core.mssql",
entityManagerFactoryRef = "secondEntityManager",
transactionManagerRef = "secondTransactionManager"
)
public class SecondConfig {
@Bean
@ConfigurationProperties(prefix = "spring.second-datasource")
public DataSource secondDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public LocalContainerEntityManagerFactoryBean secondEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(secondDataSource());
em.setPackagesToScan(new String[] {"com.sample.core.mssql.test"});
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
vendorAdapter.setGenerateDdl(true);
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> prop = new HashMap<>();
prop.put("hibernate.dialect", "org.hibernate.dialect.SQLServerDialect");
prop.put("hibernate.hbm2ddl.auto", "update");
prop.put("hibernate.format_sql", true);
em.setJpaPropertyMap(prop);
return em;
}
@Bean
public PlatformTransactionManager secondTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(secondEntityManager().getObject());
return transactionManager;
}
}
엔티티와 레파지토리를 간단하게 테스트용으로 작성해보았다.
@Entity
@Table(name = "board")
@Data
@NoArgsConstructor @AllArgsConstructor
public class BoardEntity {
@Id @Column(name = "BOARD_ID")
private String boardId;
@Column(name = "BOARD_NAME")
private String boardName;
}
@Repository
public interface BoardRepository extends JpaRepository<BoardEntity, String> {
}
@Entity
@Table(name = "post")
@Data
@NoArgsConstructor @AllArgsConstructor
public class PostEntity {
@Id
@Column(name = "POST_ID")
private String postId;
@Column(name="POST_NAME")
private String postName;
}
@Repository
public interface PostRepository extends JpaRepository<PostEntity, String> {
}
엔티티 대로 각자의 DB에 테이블이 생성되고 값이 들어가는지 테스트 해보았다.
@SpringBootTest
public class MultiTest {
@Autowired private PostService mssqlService;
@Autowired private BoardService mariaService;
@Test
@Description("mssql test")
void mssqlInsert() {
PostEntity entity = new PostEntity("post999", "sub");
mssqlService.insert(entity);
}
@Test
@Description("maria test")
void postgresqlInsert() {
BoardEntity entity = new BoardEntity("board999", "primary");
mariaService.insert(entity);
}
}


잘 생성된 것을 확인했다.
그리고 jpa 설정에 jpa 관련 프로퍼티들도 직접 설정해줘야 올바르게 동작했다.
처음에 프로퍼티를 yml 에만 작성해놓고 테스트를 수행했더니
ddl-auto 를 update 으로 설정했음에도 테이블 없다는 오류가 발생했었다.
HashMap<String, Object> prop = new HashMap<>();
prop.put("hibernate.hbm2ddl.auto", "update");
em.setJpaPropertyMap(prop);
위와 같이 primary, second 설정에 jpa 관련 프로퍼티 설정도 해줘야 한다.
참고블로그
Spring Boot | JPA, 다중 데이터베이스 구성하기
구성환경 Spring Boot 2.7.0, MariaDB 10.5.13 기존에 하나의 데이터 소스를 통해 정상 작동하는 프로젝트에서 2개 이상의 데이터 소스를 사용하기 위해 작성된 내용입니다. 기본 스프링 부트 데이터베이
kitty-geno.tistory.com
SpringBoot JPA Multiple Databases 설정
다중 DB는 Spring boot 처럼 Auto Configuration되지 않음설정파일(application.yml 또는 application.properties) 값을 읽어와서 연동 할 DB 수 만큼 Datasource를 수동 설정해야함설정파일 대신 코드로 직접 설
velog.io
JPA, JDBC의 DB MultiDataSource 적용하기
JPA와 JDBC를 동시에 쓰고 싶다! JPA 그리고 JDBC 를 동시에 사용하는 방법은 그렇게 어렵지 않다. JPA 의존성 밑에 JDBC가 포함되어있어서 JDBC template를 이미 사용할 수 있는 구조로 되어있어서 의존성
sundries-in-myidea.tistory.com