TIL - 26.02.23

이준연·2026년 2월 23일

QueryDSL


타입 세이프한 방식으로 동적 쿼리를 작성할 수 있도록 도와주는 라이브러리

핵심 개념

  • JPQL 빌더이자 도메인 전용언어(DSL)
  • SQL이 아닌, JPA 위에서 동작하는 쿼리 빌더

장점 요약

  • IDE 자동완성 지원
  • 컴파일 타임 검증
  • 동적 쿼리 작성 간결화
  • 코드 가독성 및 유지보수성 향상

QeuryDSL 설정

build.gradle

    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"

QuerydslConfig

@Configuration
public class QuerydslConfig {

    @PersistenceContext
    private EntityManager em;

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

QeuryDSL 쿼리

기본구조

queryFactory
    .select(조회대상)
    .from(대상엔티티)
    .where(조건)
    .orderBy(정렬)
    .fetch();

기본 비교 메서드

  • eq() : 같다
  • ne() : 다르다
  • gt() : 초과
  • goe() : 이상
  • contains() : 포함
  • endsWith() : 끝남

QeuryDSL 고도화

BooleanBuilder

  • 여러 조건을 동적으로 추가하거나 제거할 수 있는 가변 조건 컨테이너
  • 복잡한 검색 조건에 유용
BooleanBuilder builder = new BooleanBuilder();

if (username != null) {
    builder.and(user.username.contains(username));
}
if (email != null) {
    builder.and(user.email.contains(email));
}
if (role != null) {
    builder.and(user.roleEnum.eq(role));
}

List<User> result = queryFactory
        .selectFrom(user)
        .where(builder)
        .fetch();

BooleanExpression

  • 하나의 조건을 메서드로 정의해 조합하는 불변 표현식
  • null 조건은 자동으로 무시
private BooleanExpression usernameContains(String username) {
    return username != null ? user.username.contains(username) : null;
}

private BooleanExpression emailContains(String email) {
    return email != null ? user.email.contains(email) : null;
}

private BooleanExpression roleEq(UserRoleEnum role) {
    return role != null ? user.roleEnum.eq(role) : null;
}

List<User> result = queryFactory
        .selectFrom(user)
        .where(
            usernameContains(cond.getUsername()),
            emailContains(cond.getEmail()),
            roleEq(cond.getRole())
        )
        .fetch();

QueryDSL 연관관계 관리

기존 방식

@Entity
public class Post {
    @ManyToOne(fetch = FetchType.LAZY)
    private User user;
}

실무형 방식

@Entity
public class Post {
    private Long userId; // 연관관계 대신 ID만 저장
}

QueryDSL로 명시적 조인

List<PostResponse> result = queryFactory
    .select(Projections.constructor(PostResponse.class,
        post.content,
        user.username))
    .from(post)
    .leftJoin(user).on(post.userId.eq(user.id)) // ID 기반 Join
    .fetch();
profile
반갑습니다!

0개의 댓글