본문 바로가기
Projects/푸하하 - 개인 프로젝트

[리팩토링] QueryDSL 도입기

by 우인입니다 2023. 12. 1.

0. 현재 상황

 

미뤄왔던 QueryDSL을 도입해보려 한다.

도입해야할 시기라는 것을 가장 크게 느낀 것은 아래 쿼리메소드를 작성했을 때이다.

메소드의 이름만으로도 쿼리문을 자동으로 작성해주는 Spring Data JPA 의 기능이지만

단점으로는 저렇게 너무 길어지기도 한다.

 

 

알아보기가 어렵다.

QueryDSL는 동적쿼리를 생성하는 데에 있어서도 장점이 있지만,

한눈에 쿼리의 내용이 잘 파악이 되기도 하니 이를 기대해보며 개선해보려 한다.

 

 


1. QueryDsl 세팅

이전에 관련해서 설정을 마쳤기에 세팅관련한 자료는 아래 이전에 작성해뒀던 포스팅을 참고했다.

이전 포스팅 링크로 방법은 갈무리한다.

 

https://thiswooin.tistory.com/68

 

TIL 230801 : QueryDSL 쓰려고 정리하는 배경지식들 (Predicate)

동적 쿼리 무조건 name만 가지고 조회하는 쿼리는 정적이다. 하지만 name이 아니라 age도 같이 조건으로 user를 조회하는 쿼리가 온다면? 아니면 아예 age만 조건으로 받는다면? 순간순간 다른 경우에

thiswooin.tistory.com

https://thiswooin.tistory.com/69

 

TIL 230802 : QueryDsl 사용하기 (JPAQueryFactory)

드디어 숱한 개념정리 끝에 QueryDsl을 사용할 순간이 왔다. 정리 1. QueryDsl 은 오픈소스 라이브러리이다. 2. 쿼리를 직접 쓰는 게 아니라 코드 형태로 쿼리를 만들 수 있게 해주는 방법들 중 하나다.

thiswooin.tistory.com

 


 

2. 리팩토링

기존코드

    Page<Quiz> findByQuizUserDatas_UserAndQuizUserDatas_IsShowHintTrueAndQuizUserDatas_IsSolvedFalse(User user, Pageable pageable);

 

 

 

QueryDsl 적용 코드

public Page<Quiz> selectMyCheckedHintQuizzes(User user, Pageable pageable) {

        QQuiz quiz = QQuiz.quiz;
        QQuizUserData quizUserData = QQuizUserData.quizUserData;

        List<Quiz> results = jpaQueryFactory
                .select(quiz) // refactor select() 안에 Projection 객체를 넣어줄 수 있다
                .from(quiz)
                .join(quizUserData).on(quizUserData.quiz.eq(quiz))
                .where(quizUserData.user.eq(user)
                    .and(quizUserData.isShowHint.isTrue())
                    .and(quizUserData.isSolved.isFalse())
                )
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();


        Long count = jpaQueryFactory
                .select(quiz.count())
                .from(quiz)
                .join(quizUserData).on(quizUserData.quiz.eq(quiz))
                .where(quizUserData.user.eq(user)
                        .and(quizUserData.isShowHint.isTrue())
                        .and(quizUserData.isSolved.isFalse())
                )
                .fetchOne();

        assert count != null;
        return new PageImpl<>(results, pageable, count);
    }

 

 

개선이라고 봐야할 지 헷갈릴 정도로 코드양이 늘었다.

Page객체를 반환해주기 위해 Count를 구하는 쿼리를 추가로 날려줬다.

fetchResult()를 통해 getTotal()하는 방식은 성능저하의 우려가 있다고 한다.

 

 


3. 느낀 점

 

쿼리를 파악하기 쉽다.

위의 장점을 기대한 것이기도 하다. 확실히 어떤 쿼리인지 파악하기도 쉽고,

처음 쿼리를 만들 때 오류를 발견하기도 쉽다는 것도 동의한다.

 

도전해볼 것

이번에는 다양한 조건으로 검색기능을 추가하며 이를 통한 동적쿼리 생성에 도전해볼까한다.

(진행중)

 

 

 


참고링크

https://jojoldu.tistory.com/372

https://jddng.tistory.com/345