[Querydsl] Querydsl을 알고 쓰고 싶었다.

Eunbi Lee·2024년 6월 2일

MDP

목록 보기
6/6
post-thumbnail

GitHub MDP repo는 다음과 같다.

1. 배경

JPA를 써보고 싶어서 시작한 프로젝트였기에, 간략한 개념만 습득한 채 JPA를 써보던 중..
조인 연산을 수행해야 하는 요구 사항을 마주하게 되었다.

type 테이블의 type_name, total_score / category 테이블의 category_name, summary를 조회하기

즉, 하나의 테이블에서 필드를 조회하는 것이 아니라 두 개의 테이블에서 여러 필드를 조회해야하는 상황을 맞닥뜨리게 되었다.

따라서, JPA에서의 조인 연산을 수행할 수 있는 방법을 몇 가지 찾아보게 되었다.

  • 조인 연산은 조회 연산에 비해 복잡한 축에 속하고, JPA에서 지원하는 `메서드 네이밍 규칙 (ex. findBy ~ ,findAll())을 따르는 조회 쿼리 메서드로 작성할 수 없기 때문이었다.

그러던 중 Querydsl을 알게 되었다.

2. Querydsl

(1) 개념

우선 Querydsl을 알아보기에 앞서서, ~dsl은 무슨 뜻일까?

dsl의 사전적 정의는 다음과 같다.

DSL(Domain Spectific Languages)
특정 도메인에서 발생하는 문제를 효과적으로 해결하기 위해 설계된 언어

dsl의 예시는 다음과 같다.

  1. SQL : 데이터베이스 내의 정보를 검색, 삽입, 수정, 삭제하기 위한 언어
  2. CSS : 웹의 디자인, 레이아웃 및 시각적 스타일링을 정의하기 위한 언어
  3. Regex(정규 표현식) : 문자열 내에서 특정 패턴을 검색, 추출, 교체하기 위한 언어

즉, Querydsl은 다음과 같이 정의할 수 있다.

SQL 형식의 쿼리를 Type-safe하게 생성할 수 있도록 하는 DSL을 제공하는 라이브러리

그리고, Querydsl은 실제로 다양한 모듈을 제공 중이다!

  • 이 중, 나는 JPA를 사용할 것이다.

(2) Querydsl 적용

지금부터 Querydsl을 프로젝트에 적용해보자.

우선, 나의 프로젝트 스펙은 다음과 같다.

  • Spring Boot (3.2.4)
  • Intellj IDE (2023.2.6)
  • Greadle (8.5)
  • querydsl (5.0.0)

a. build.gradle에 Querydsl 의존성 추가하기

b. QClass 생성을 위한 annotationProcessor 추가하기

이때, QClass란 다음과 같다.

엔티티 클래스 속성과 구조를 설명해주는 메타데이터

추가로, type-safe하게 쿼리 조건 설정 가능하다고 하는데, ..

  • 이 부분은 좀 더 공부해봐야 체감이 될 것 같다.

c. QClass 생성하기

Querydsl은 build.gradle에 implementation 및 annotationProcessesor를 추가한 후, QClass가 생성되어야 실행할 수 있다.

따라서, gradle - task - other - compileJava를 실행하면 된다.

이후, 생성된 QClass를 /src/main/generated에서 확인할 수 있다.

추가로, Gradle이나 Intellj의 기본 설정에 따라 Querydsl 실행 여부가 달라질 수 있으므로, 다음과 같은 스크립트를 추가한다.

  • 이때, grc/main/generated는 Qclass가 생성되는 경로이다.

참고로, Gradle과 Intellij 설정에 따른 QClass 파일 생성 위치는 다음과 같다.

  • Gradle 기본 설정

  • Intellij 기본 설정

d. .gitignore 추가

위에서 추가한 grc/main/generated는 git에 업로드 될 때, 필요하지 않은 파일이므로 추가하도록 한다.

여기까지가 기본적인 세팅이었다!

이제는 실제 프로젝트 코드를 통해 Querydsl을 사용해보자.

(3) Querydsl 사용

구현하고자 하는 기능의 요구 사항은 다음과 같다.

쉬움 / 보통 / 어려움 난이도에 따라 설문 수행에 대한 자세한 설명문을 나타내기

이를 정리해보면?

  1. 난이도는 QueryString 값으로 받는다.
  2. 최종적으로, type 테이블의 typeName과 동일한 컬럼값들을 가져오면 된다.
  • type : typeName, content, totalScore
  • category : sumarry(List), categoryName(List)
  1. 이때, 두 테이블의 컬럼들을 동시에 조회해와야 하므로 조인 연산조인 테이블이 필요하다.
  2. 따라서, 조인 연산은 QueryDSL / 조인 테이블은 typeCategory을 설계하도록 한다.

이제부터 typeCategory 테이블을 통해 Querydsl을 사용해보자!

typeCategory는 다음과 같이 구현했다.

그리고, 조인 테이블이므로 복합키를 가지고 있기에 ID Class를 만들어줘야만 한다.

a. JPA repository 선언

사용할 JPA repository를 선언한다.

이때, 나중에 구현할 Custom Class를 추가해줘야 한다.

b. JPAQueryFactory 빈 등록

JPA를 통해서 조회하기 때문에, entityManger를 추가하자.

c. CustomRepository 인터페이스 생성

구현하고자 하는 메서드들을 정의한다.

(1) findSurveyDescription() : typeName / content / .. 등을 조회할 메서드

(2) findCategoryNamesByType() : categoryName(List)를 조회할 메서드

(3) findSummariesByType() : summary(List)를 조회할 메서드

d. Impl 클래스 생성

Custom 클래스에서 정의한 메서드를 구현한다.

개인적으로, fetchOne()인지 fetchFirst()인지로도 고생을 많이 했었는데.. 이는 주제에서 약간 벗어나는 내용이라고 생각하여, 참고한 블로그 링크만 남겨놓겠다.

이렇게 하고, 실행을 하면 ~ 정상적으로 값을 조회했음을 알 수 있다.

3. 정리

이러한 Querydsl을 직접 써보면서, 장점 및 단점을 간략히 추려보았다.

장점

  1. NativeQuery 또는 JPQL을 쓸 당시에는, @Query 어노테이션을 통해 쿼리를 작성했기에.. 보다 가독성이 좋다는 장점이 있다.
  2. 여전히 findBy~와 같은 메서드 네이밍을 따르기에 쿼리 조건 또는 정렬 방식을 유추할 수 있다.
  3. 메서드 분리를 통한 재사용성 향상을 누릴 수 있다.
  4. Type-safe한 QClass를 통한 문법으로 인한 런타임 에러를 방지할 수 있다.

단점

  1. 1차 캐시의 장점을 누릴 수 없다.
  • 이 부분은 결국 Querydsl은 JPA가 아니라 JPQL 빌더이기 때문에 발생하는 문제인 것까지는 이해했지만, 그 이상은 이해하지 못했기에 아래에 관련 링크를 기재하겠다.
  1. Querydls의 마지막 업데이트는 JAVA 8 기준으로 (2021.07)이다.
    따라서, 향후 업데이트가 되지 않을 수도 있다는 것을 유념하고 사용하면 좋을 것 같다.

Reference

참고하면 좋을 자료

profile
안녕하세요, 개발자 비비입니다.

0개의 댓글