MKISOS 2025. 8. 4. 06:05
반응형

Querydsl 정리

이 글은 인프런 김영한님의 "스프링 DB 2편 - 데이터 접근 활용 기술" 강의를 수강하고 정리한 내용이다.

 

Querydsl은 자바 코드로 타입 안전(type-safe)하게 SQL/JPA 쿼리를 작성할 수 있도록 도와주는 프레임워크다. 특히 복잡한 조건의 동적 쿼리를 작성할 때 코드의 가독성과 안정성을 높여주기 때문에, 실무에서 매우 유용하게 활용된다고 한다.


1. 기존 쿼리 방식의 문제점

JPQL 방식

String query = "select m from Member m " +
               "where m.age between 20 and 40 " +
               "and m.name like '김%' " +
               "order by m.age desc";
  • 장점: SQL과 유사해서 빠르게 익숙해질 수 있다.
  • 단점: 문자열 기반, 타입 체크 불가, 오타 발견이 런타임에 발생

Criteria API

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Member> cq = cb.createQuery(Member.class);
Root<Member> m = cq.from(Member.class);
cq.select(m)
  .where(cb.between(m.get("age"), 20, 40),
         cb.like(m.get("name"), "김%"))
  .orderBy(cb.desc(m.get("age")));
  • 장점: 동적 쿼리 구성 가능
  • 단점: 너무 복잡하고 가독성이 낮아 실무에서 거의 사용되지 않는다

2. Querydsl 소개

Querydsl은 위 두 가지 방식의 문제를 모두 해결할 수 있다. 타입 안전, 자동완성 지원, 메서드 체이닝 문법, 동적 쿼리 조합까지 자바 개발자에게 익숙한 방식으로 쿼리를 작성할 수 있다.

List<Member> list = queryFactory
    .select(member)
    .from(member)
    .where(member.age.between(20, 40).and(member.name.like("김%")))
    .orderBy(member.age.desc())
    .limit(3)
    .fetch();

SQL 오타로 인한 런타임 오류를 컴파일 시점에 막을 수 있고, IDE 자동완성의 도움을 받을 수 있어 생산성이 높아진다.


3. Querydsl 설정

스프링 부트 3.x 기준 (jakarta)

implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"

Q타입 생성 확인

  • Gradle: ./gradlew clean compileJava
  • IntelliJ: Build > Build Project 또는 테스트 실행
  • 생성 경로: build/generated/sources/annotationProcessor/java/main/QMember.java

Q클래스는 빌드시 자동 생성되므로 git 버전 관리에 포함하지 않는 것이 일반적이다.


4. Querydsl 적용 예시

저장소 구현체 예시

public class JpaItemRepositoryV3 implements ItemRepository {
    private final JPAQueryFactory query;
    ...
    public List<Item> findAll(ItemSearchCond cond) {
        return query
            .select(item)
            .from(item)
            .where(likeItemName(cond.getItemName()),
                   maxPrice(cond.getMaxPrice()))
            .fetch();
    }

    private BooleanExpression likeItemName(String itemName) {
        return StringUtils.hasText(itemName) ? item.itemName.like("%" + itemName + "%") : null;
    }

    private BooleanExpression maxPrice(Integer price) {
        return price != null ? item.price.loe(price) : null;
    }
}

null을 where 절에 넘기면 자동으로 조건에서 제외되는 구조를 활용해, 동적 쿼리를 매우 간결하게 작성할 수 있다.


5. Querydsl의 장점

타입 안전성 컴파일 시점에 오타, 잘못된 속성 검출 가능
자동완성 지원 IDE 지원을 통한 빠른 개발 가능
동적 쿼리 BooleanBuilder 또는 null 조건 조합으로 간결한 구성 가능
쿼리 재사용 조건 메서드를 재활용 가능 (likeName(), maxPrice() 등)
정적 타입 생성 Q클래스를 통해 명확하게 쿼리 경로를 제시함

6. 실무 적용 팁

  • JPAQueryFactory는 스프링 빈으로 등록해 재사용할 수 있다.
  • @Repository를 붙여 스프링 예외 변환이 자동으로 적용되도록 한다.
  • 복잡한 조건의 쿼리는 Querydsl로, 단순한 조건은 SpringData JPA의 메서드 쿼리 방식으로 병행 사용한다.

7. 정리

Querydsl은 자바 코드만으로 동적이고 복잡한 쿼리를 안전하고 간결하게 작성할 수 있는 도구다. 특히 실무에서 동적 검색 조건이 많은 화면, 복잡한 페이징 조회, DTO 변환이 필요한 API에서 Querydsl은 필수적인 기술로 자리 잡았다.

반응형