Skip to content

QueryDsl 적용

Robin Choi edited this page Apr 6, 2022 · 6 revisions

1. 도입 이유

Spring Data Jpa를 사용하게 되면 save, find와 같은 주요 메서드는 제공해주지만 커스텀이 필요한 메소드의 경우, @Query어노테이션을 사용한 JPQL을 사용한다. 아래와 같이, 쿼리를 짜게 되면 먼저 개행이 포함되기 때문에 가독성이 상당히 떨어진다. 또한, 문자열에 오타나 문법적인 오류가 존재할 때 정적쿼리가 아닐 경우 런타임 시점에서 에러가 발생하여 에러의 원인을 찾기가 상당히 불편해진다.

기존 코드

@Query(value = "select p " +
            "from Post p join p.account left join p.postLike " +
            "where p.account.id = :accountId " +
            "AND p.board = :board and p.category = :category " +
            "ORDER BY p.created desc")
    public List<Post> findAllPost(@Param("accountId") Long accountId, @Param("board") String board, @Param("category") String category);

2. 문제 상황

앞서 말했다시피, 쿼리하나에 3~4줄의 개행이 포함된 쿼리를 작성하는 경우가 굉장히 많았다. 특히 우리 프로젝트 특성상 아트워크, 포스트 엔티티의 경우 쿼리 리팩토링을 하기 전 초반에는 조인이나 레프트 조인을 여러번 필요로 했고, 이 때 JPQL을 사용하게 되면 가독성 뿐만 아니라 문제 발생시 원인을 찾는데 소요시간이 많이 걸릴 것이라고 판단하였다.

3. 해결 방안

Data-jpa에서 사용할 수 없는 코드는 전부 커스텀 레포지토리를 인터페이스로 구현하고, 그에 대한 구현코드는 QueryDsl을 도입해서 사용하는 방법을 찾을 수 있었다.

4. 의견 결정

QueryDsl은 HQL(Hipernate Query Language)쿼리를 타입에 안전하게 생성 및 관리할 수 있는 프레임워크로, 자바코드로 쿼리를 만들기 때문에 컴파일 시점에서 오류를 잡을 수 있고 가독성 측면에서도 훨씬 우수하게 읽혀 프로젝트의 작업 속도에도 큰 영향을 미쳤다. 또한 전체보기와 같이 카테고리가 설정되지 않아 null로 들어오는 쿼리의 경우 Boolean Expression을 추가로 사용할 수 있어 파라미터의 null처리에도 우수하게 작용했다.

@Override
    public List<ArtworkMain> findAllArtWork(Long lastArtworkId, String category) {
        return queryFactory
                .select(Projections.constructor(ArtworkMain.class,
                        artWorks.id,
                        account.id,
                        account.nickname,
                        account.profileImg,
                        artWorks.thumbnail,
                        artWorks.view,
                        artWorkLikes.count(),
                        artWorks.category,
                        artWorks.created
                ))
                .from(artWorks)
                .join(account).on(account.id.eq(artWorks.account.id))
                .leftJoin(artWorkLikes).on(artWorkLikes.artWorks.eq(artWorks))
                .limit(10)
                .where(isLastArtworkId(lastArtworkId),
                        isCategory(category),
                        artWorks.scope.isTrue())
                .groupBy(artWorks.id)
                .orderBy(artWorks.created.desc())
                .fetch();
    }

private BooleanExpression isCategory(String category) {
        return category.isEmpty() ? null : artWorks.category.eq(category);
    }

5.레퍼런스

Spring Boot에 QueryDSL을 사용해보자
[QueryDSL] JPQL vs Query DSL
Querydsl: 소개와 사용법

Clone this wiki locally