QueryDSL

SIHA·2025년 3월 18일

1.QueryDSL 소개

QueryDSL이란?

Querydsl은 정적으로 타입이 지정된 SQL 유사 쿼리를 작성할 수 있도록 해주는 프레임워크이다. 문자열로 직접 쿼리를 작성하거나 XML 파일로 관리하는 대신, Querydsl의 플루언트 API를 통해 코드로 쿼리를 구성할 수 있다.

플루언트 API? 메서드 체이닝을 통해 마치 자연어 문장처럼 연속적으로 호출하여 코드를 작성하는 방식 (점으로 이어서 연결하는 형태의 API)

QueryDSL의 필요성과 장점

  • Type-safe
    QueryDSL은 컴파일 시점에 쿼리 오류를 발견할 수 있도록 도와주는 Type-safe 쿼리 작성 방식을 제공한다.
  • 코드를 문자열이 아닌 코드 형태로 작성할 수 있어 컴파일 시점에 오류를 확인할 수 있다.
  • 인텔리제이와 같은 IDE의 자동완성 기능의 도움을 받을 수 있어 생산성을 높일 수 있다.
  • 복잡하거나 동적인 쿼리 작성이 편리하다.
  • 쿼리 작성 시 자주 사용하는 조건 등을 메서드 추출을 통해 재사용할 수 있다.
  • JPQL 문법과 유사해 쉽게 학습할 수 있다.
  • 엔티티 변경 시에도 Q클래스 자동 생성으로 쿼리 코드의 일관성을 유지할 수 있다.

2. 프로젝트 적용 방법

Gradle 의존성 추가

Q-Type 생성 설정

Q-Type이란?

Q-Type은 엔티티를 기반으로 QueryDSL이 자동 생성해주는 클래스로, 예를 들어 User 엔티티가 있으면 QUser라는 클래스를 자동 생성하며, 해당 클래스 안에는 엔티티의 각 필드가 속성으로 정의 된다.

Q-Class 자동 생성 확인 및 관리

Q-Class는 build/generated 디렉토리에 생성된다. 보통 build/generated/querydsl 폴더 안에 Q클래스들이 위치하며, 생성된 클래스는 수정하지 않고 자동으로 관리된다.

Q-Class란?

Q-Class는 QueryDSL 쿼리를 타입 안전하게 작성하기 위해 생성되는 자동화된 클래스로, 엔티티 필드를 코드 자동완성으로 가져올 수 있도록 지원한다.

3. QueryDSL 기본 사용법

JPAQueryFactory

@Configuration
public class JPAConfiguration {

    @PersistenceContext
    private EntityManager entityManager;

    @Bean
    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
        return new JPAQueryFactory(entityManager);
    }
}

JPAQueryFactory는 QueryDSL에서 쿼리를 작성할 때 사용하는 주요 객체로, 빈으로 등록해서 사용한다.

기본 SELECT 쿼리 작성

QUser user = QUser.user;

List<User> result = queryFactory
    .selectFrom(user)
    .fetch();
  • fetch(): 결과 리스트 반환
  • fetchOne(): 단일 결과 반환 (없으면 null, 두 개 이상이면 예외)
  • fetchFirst(): 첫 번째 결과 반환(limit(1)과 유사)

조건절 작성 방법

User result = queryFactory
    .selectFrom(user)
    .where(User.username.eq("John"))
    .fetchOne();

DISTINCT

List<String> names = queryFactory
    .select(user.username)
    .distinct()
    .from(member)
    .fetch();

4. 조인과 관계형 쿼리

Inner Join

List<Todo> result = queryFactory
    .selectFrom(todo)
    .join(todo.user, user)
    .where(team.name.eq("john"))
    .fetch();

Left Join

List<Member> result = queryFactory
    .selectFrom(todo)
    .leftJoin(todo.user, user)
    .fetch();

Fetch Join

Todo findTodo = queryFactory
    .selectFrom(todo)
    .join(todo.user, user).fetchJoin()
    .where(todo.id.eq(todoId))
    .fetchOne();

on절 조건 조인 예시

List<Tuple> result = queryFactory
    .select(member, team)
    .from(member)
    .leftJoin(member.team, team)
    .on(team.name.eq("teamA"))
    .fetch();

서브 쿼리

QMember memberSub = new QMember("memberSub");

List<Member> result = queryFactory
    .selectFrom(member)
    .where(member.age.eq(
        JPAExpressions
            .select(memberSub.age.max())
            .from(memberSub)
    ))
    .fetch();

5. 동적 쿼리 작성

BooleanBuilder

BooleanBuilder는 동적 쿼리를 작성할 때 여러 조건을 유연하게 조합할 수 있도록 지원한다.

BooleanBuilder builder = new BooleanBuilder();
if (username != null) {
    builder.and(member.username.eq(username));
}
if (age != null) {
    builder.and(member.age.eq(age));
}

List<Member> result = queryFactory
    .selectFrom(member)
    .where(builder)
    .fetch();

Where절 다중 조건

List<Member> result = queryFactory
    .selectFrom(member)
    .where(
        member.username.eq("John"),
        member.age.gt(20)
    )
    .fetch();
profile
뭐라도 해보자

0개의 댓글