[Spring JPA] — Multiple Databases 설정(w/ kotlin, Querydsl)

bae.200.ok
6 min readOct 2, 2022
1 개요
2 배경
3 DataSourceConfig 작성
3.1 PrimaryDataSourceConfig
3.2 SecondaryDataSourceConfig
3.3 @SecondaraDataSource 어노테이션
3.4 주의사항 - 다중 profile 상황에서 profile은 어떻게 적용할 수 있을까?
3.4.1 삽질 및 삽질 후기
4 EntityManager 설정
5 Transaction 설정
6 마무리

1 개요

개인정보를 처리하다보니 메인 DB에서 삭제된 사용자를 별도로 관리하기 위한 DB가 필요하게되었다. 그래서 하나의 애플리케이션 안에서 다중 DB를 연결하여 사용하는 방법을 정리했다.

2 배경

다중 DB를 연결할 때에 몇 가지 삽질한 부분이 있다. 하나씩 풀어가보자.

  • 다중 profile 설정
  • Querydsl에서 EntityManager 설정
  • Transaction 설정

3 DataSourceConfig 작성

  • Primary: 메인으로 사용하는 DB
    > UserRepository(UserEntity)
  • Secondary: 위에서 언급한 별도의 데이터를 관리하기 위한 DB(네이밍을 실제로 `secondary`라고 하지 않는다. 적절한 이름을 짓자)
    > DeletedUserRepository(DeletedUserEntity)

3.1 PrimaryDataSourceConfig

3.2 SecondaryDataSourceConfig

3.3 @SecondaraDataSource 어노테이션

위에서 @SecondaryDataSource 라는 어노테이션을 볼 수 있는다. 이를 통해 얻는 것은 다음과 같다.

  • @Primary@Qualifier를 구분지어 스프링 빈을 주입하기 위해 작성되었다. 즉, PrimaryDataSourceConfigSecondaryDataSourceConfig를 구분지어 사용하기 위함이다.
  • ⭐️@Qualifer만 사용하면되는데 직접 어노테이션을 작성한 이유는 컴파일 시 타입 체크가 가능하다는 점 때문이다.

3.4 주의사항

— 다중 profile 상황에서 profile은 어떻게 적용할 수 있을까?

실제 서비스를 개발한다면 환경을 구분짓는다. 팀마다 다르겠지만, local/qa/op 는 거의 무조건 구분을 지을 것이다. 그렇다면 이에 따라 여러profile 파일이 나올 것이다.

특정 profile로 서버를 동작시켰을 때에, profile 정보를 어떻게 DataSourceConfig에 적용시킬 수 있을지 많은 삽질을 했다.

✅ 결론부터 말하면, @EnableConfigurationProperties를 사용하면 된다.

3.4.1 삽질 및 삽질 후기

역시나 대충보면 안된다는 교훈을 얻었다.

`@PropertySource` 삽질의 시작

나의 경우 profile을 yaml 파일로 정의해서 사용중이었다.

  • application.yml
  • application-local.yml
  • application-qa.yml
  • application-op.yml

@PropertySource를 보면 properties 파일을 path 기반으로 설정하는 것을 볼 수 있다. 그래서 다중 profile의 경우 모든 path를 입력하면 된다고 생각했다.

사실 이때부터 조금 귀찮고 복잡하다는 생각이 들었었다.(어색하고 ‘이런것도 안해줘?’라고 생각했을 때 더 검색을 했어야 했다.)

@PropertySource는 yaml 파일을 지원해주지 않아서 yaml 파일을 읽어서 property로 할당해주는 Custom PropertySourceFactory를 만들어야했다.

또한, @PropertySource에는 SpEL 사용이 불가능했다. 그래서 모든 path를 입력해야한다고 생각했다.

그래서 아래처럼 작성했었다.

결과는 처참했다. 실행 시 적용했던 profile은 적용되었지만, 불완전하게 적용되었었다. 무슨 말이냐하면, applicatoin.yml에서 default로 local이 적용되도록 처리했는데, 실행 시 적용했던 profile이 아닌 local property가 적용되었다.

4 EntityManager 설정

Querydsl을 사용할 때에 DataSource에 따른 entityManager를 주입해주어야한다.

아래와 같은 클래스의 setEntityManager메서드를 통해서entityManager를 할당할 수 있다.

이를 확장하여 Repository를 작성할 때에 사용할 abstract class를 만들 수 있다.

실제 사용은 아래와 같이 한다.

5 Transaction 설정

다중 datasource 설정에 따라 transaction을 관리할 필요가 생긴다. 이번 글에서는 여러 트랜잭션을 하나의 트랜잭션으로 관리하는 내용은 소개하지 않는다. 아래 참고 링크에 자세한 내용이 안내되어져 있다.

특정 Service를 사용할 때에 특정 transaction을 사용하도록 설정해보자.

이때 javax.transaction이 아닌 org.springframework.transaction을 사용해야한다. 그래야 transactionManager를 지정하는 게 가능하다.

6 마무리

DB 커넥션의 경우 Spring Framework가 제공한다. 다중 DB를 연결하면서 ‘아직 나는 Spring Framework가 DB 커넥션을 관리하는 방식을 완벽하게 이해하고 있지 못하고 있다.’고 생학하게 되었다.

설령 내가 알고 있는데 전부라고 해도, ‘그게 전부인가’라는 확신이 들지 않는다. 다시한번 정리할 필요가 있다.

[추가로 확인할 키워드]

  • JpaContext
  • 다중 DB 트랜잭션 관리(TransactionManager)

--

--