[Back-end] JPA를 사용하여 통계 개발 with QueryDSL

 Pi Battle Game 을 개발하면서 JPA를 채택한 이유는 보일러플레이트(Boilerplate)를 방지하기 위해서였습니다.


JPA가 구현체를 만들어주는 메소드들만 사용할 경우 아쉬운 점들이 있는데요

1. 직접적인 연관관계를 맺지 않는 join이 어렵습니다 (예 : 서브쿼리)

2. entity의 필드가 아닌 항목들을 select 하는 것에 한계가 있습니다. (예 : max, sum, rank)


JPA에서 복잡도 높은 쿼리를 구현하려면 어떻게 하면 될까요?

물론 어노테이션을 써서 native query 작성하면 되겠지만... 개발자의 자존심에 어쩐지 허락하지 않습니다.

'비즈니스를 코드에 녹여서 쿼리 잔업을 줄이려고 기껏 JPA를 써놓고 네이티브 쿼리로 대체하겠다고?'

'이 정도 쿼리면 뭐 많이 복잡한 쿼리도 아닌데 겨우 이 정도로 네이티브를 써야 하나...' 


그래서 SRR이 채택한 방법은 바로 QueryDSL입니다.

Query DSL과 JPA를 함께 사용한다면 아래와 같이 구현해주어야 합니다.

(참고 : Spring Data JPA 공식 Docs)

(출처 : 이노그리드 공식블로그)


위 예시의 점선은 implements, 실선은 extends입니다. 

JpaRepository는 빌드를 하더라도 그 구현체(implement)가 없기 때문에 Interface로서 사용하게 되어 있습니다. 대신, 런타임에 프록시를 이용해 동적으로 구현합니다.

이를 통해서 우리는 JpaRepository를 상속받은 Repository 인터페이스에서 QueryDslRepository를 상속받는 것으로 Spring Data JPA의 기능과 QueryDSL의 기능을 동시에 활용할 수 있습니다.

스프링은 JpaRepository 인터페이스를 상속받는 Repository 인터페이스를 찾으면, 이를 구현하는 프록시 객체를 생성하여 직접 기본 제공 기능을 구현합니다. 그리고 자동으로 QueryDslRepository을 상속받은 QueryDslRepositoryImpl은 스프링 빈으로 등록됩니다.
(그래서 반드시 명명규칙을 QueryDslRepository 이름 + 'Impl' 로 해주어야 합니다.)

따라서 Repository 인터페이스를 사용하는 클라이언트는 JpaRepository의 기능과 QueryDslRepository의 기능을 동시에 사용할 수 있게 되는 것이죠.



댓글

이 블로그의 인기 게시물

Google Play Stroe 출시 리젝 "발견된 문제: 부적절한 광고 정책 위반" 해결 방법

[Unity] Google Mobile Ads SDK 활용하여 광고 삽입하기