묘미 프로젝트를 진행하면서, 클릭한 상품 정보와 상품에 달린 문의, 리뷰, 베스트 리뷰 정보를 한번에 조회해야 했다.
전체 ERD
상품, 문의, 리뷰, 베스트 리뷰, 판매자 ERD
ERD 상으로는 간단해 보이나, 실제 Spring Boot 환경에서 JPA로 구현했을 때 복합키는 따로 Embedded 클래스로 구현해 놓은 것도 있고 워낙 연관관계가 많다보니 N+1 문제는 물론이고 엄청난 순환참조가 일어났었다.
상품을 select하는데 상품이 가지고 있는 판매자의 정보를 select 하고, 또 판매자가 가지고 있는 회원의 정보를 select 하고, 회원이 가지고 있는 멤버십의 정보를 select하고...
꼬리의 꼬리를 무는 sql query를 만날 수 있었다.
순환참조로 인한 에러와 너무나 떨어지는 성능에 JPA를 괜히 사용했나 싶었다.
그렇다고 service단에서 상품 조회 쿼리 한번, 리뷰 조회 쿼리 한번, 문의 조회 쿼리 한번... 이런식으로 필요한 정보마다 각각의 쿼리를 날리는 것 또한 성능이 매우 떨어졌고 이 또한 지독한 쿼리들을 많이 만났다.
select 쿼리로 무한 스크롤을 경험했다...
처음에는 Spring Data JPA가 기본적으로 제공해주는 CRUD 메서드 및 쿼리 메서드 기능을 사용했다. 그러다가 원하는 조건의 데이터를 얻기 위해 필연적으로 JPQL을 작성했는데, 간단한 로직에는 문제가 없었지만 복잡한 로직의 경우....쿼리 문자열이 상당히 길어졌다.
처음에는 그래서 네이티브 쿼리를 사용했었다. 그런데 네이티브 쿼리를 무의식적으로 여기저기 쓰다보니 현타가 세게 왔는데. 이유는 '이러면 굳이 JPA를 쓸 필요가 있었나? Mybatis를 쓰는게 더 낫지 않나?' 라는 의문이 계속 들었기 때문이다.
그렇다고 열심히 만들어 놓은 연관관계를 지금와서 끊어주기엔... 우리 팀의 노력이 엄청났고 Spring Boot 프로젝트인 만큼 Spring Data JPA를 꼭 써보고 싶었기 때문에 다른 방법을 찾기 시작했다.
그러다가 우아한형제들 기술블로그에서 QueryDSL에 대해서 처음 알게 되었다.
처음에는 JPA관련 자료를 찾다가 읽게되었고 그때는 내가 필요하지 않은 프레임워크라 생각해서 무심코 지나쳤는데 팀원분과 얘기하다가 이게 나한테 너무 필요하다! 싶어서 다시 찾아보게되었다.
QueryDSL의 장점
1. 문자가 아닌 코드로 쿼리를 작성하므로 컴파일 시점에 문법 오류를 쉽게 확인할 수 있다.
2. 자동 완성 등 IDE의 도움을 받을 수 있다.
3. 동적 쿼리 작성이 편리하다.
4. 쿼리 작성시 제약 조건 등을 메서드 추출을 통해 재사용할 수 있다.