QueryDSL

[Querydsl] QueryDSL 란?

쌈뽕코딩 2025. 2. 17. 18:16

QueryDSL은 타입 안전(Type-Safe)한 동적 쿼리를 생성할 수 있도록 지원하는 Java 기반 ORM(Object-Relational Mapping) 프레임워크이다. JPA(Java Persistence API)를 사용할 때 JPQL(Java Persistence Query Language) 또는 Criteria API를 대체할 수 있도록 설계되었다.

 

✏️ 타입 안전한 동적 쿼리란?

BooleanBuilder builder = new BooleanBuilder();
if (age != null) {
    builder.and(m.age.gt(age)); // 나이가 age보다 큰 조건 추가
}
if (name != null) {
    builder.and(m.name.eq(name)); // 이름이 같은 조건 추가
}

List<Member> members = queryFactory
    .selectFrom(m)
    .where(builder)
    .fetch();

 

  • 동적 쿼리란 실행 시점에서 조건이 변경되는 쿼리다. 예를 들어, 사용자가 입력한 조건에 따라 age, name, city 등의 필터를 조합하는 경우 QueryDSL을 사용하면 안전하게 동적 쿼리를 생성할 수 있다.
  • 그렇다면 "타입 안전한(Type-Safe) 동적 쿼리"라는 말은 컴파일 시점에 데이터 타입을 검증할 수 있는 방식으로 동적으로 생성되는 SQL 쿼리를 의미한다. 즉, 실행하기 전에 문법 오류나 타입 오류를 체크할 수 있어 런타임 오류를 방지할 수 있다.

✏️ JPQL이란?

String jpql = "SELECT m FROM Member m WHERE m.age > " + age;
List<Member> members = em.createQuery(jpql, Member.class).getResultList();
  • JPQL(Java Persistence Query Language)은 JPA에서 엔티티 객체를 대상으로 SQL과 유사한 쿼리를 작성하는 객체 지향 쿼리 언어이다.
  • SQL과 유사하지만, SQL이 데이터베이스 테이블을 대상으로 하는 반면 JPQL은 엔티티 객체를 대상으로 동작한다.
  • JPA의 @Query 어노테이션과 함께 사용 가능

 

📌 1. 타입 안전성이 없는 JPQL(문자열 기반 쿼리) 예제

String jpql = "SELECT m FROM Member m WHERE m.age > " + age;
List<Member> members = em.createQuery(jpql, Member.class).getResultList();

 

 

🔴 문제점

  • 문자열(String)로 쿼리를 작성하기 때문에 컴파일 타임에 문법 오류를 체크할 수 없음
  • 오타(예: m.aga → m.age 오타)를 내도 런타임까지 알 수 없음
  • 필드 타입이 바뀌더라도 쿼리는 자동으로 검증되지 않음

📌 2. QueryDSL을 활용한 타입 안전한 동적 쿼리 예제

QMember m = QMember.member;

List<Member> members = queryFactory
    .selectFrom(m)
    .where(m.age.gt(20))  // age 필드는 int 타입으로, 문자열 오류 방지
    .fetch();

 

타입 안전성 확보

  • m.age가 int 타입이므로, m.age.gt("20") 같은 실수는 컴파일 오류로 감지 가능
  • 필드명이 변경되거나 오타가 있어도 컴파일 타임에 오류를 알려줌
  • 자동완성 기능 제공 (IDE에서 지원)

그럼 왜 QueryDSL을 사용해야 할까?

📌 예제 코드 (JPQL vs QueryDSL 비교)

// jpql 사용
String jpql = "SELECT m FROM Member m WHERE m.age > :age";
List<Member> members = em.createQuery(jpql, Member.class)
                         .setParameter("age", 20)
                         .getResultList();
// querydsl 사용
QMember m = QMember.member;
List<Member> members = queryFactory
                        .selectFrom(m)
                        .where(m.age.gt(20))
                        .fetch();
  • JPA를 사용할 때 JPQL을 직접 작성하면 문자열 기반이라 가독성이 떨어지고 유지보수가 어렵다.
  • Querydsl이 더 간결하고 직관적이며, 타입 안정성이 보장됨

QueryDSL은 코드 기반으로 작성되므로, 아래와 같은 장점이 있다.

 

1. JPQL 대비 장점

  • 문자열 기반이 아니라 코드 기반이라 유지보수 쉬움
  • 컴파일 타임 오류 체크 가능 → 런타임 오류 감소
  • 동적 쿼리 작성이 편리

2. Criteria API 대비 장점

  • 더 직관적이고 가독성이 뛰어남
  • 코드량이 줄어들어 유지보수 비용 절감

3. JPA와의 강력한 연동 지원

  • Spring Data JPA와 함께 사용하면 복잡한 쿼리도 간단하게 작성 가능
  • fetchJoin, GroupBy, having 등 SQL의 다양한 기능 활용 가능

QueryDSL의 대체 기술에는 어떤 것이 있을까?

  1. Spring Data JPA (Specifications 포함)
    • Spring Data JPA에서 Specification을 활용하여 동적 쿼리를 생성 가능
    • Querydsl 없이도 복잡한 동적 쿼리를 작성할 수 있지만 가독성은 Querydsl보다 떨어짐
  2. JPA Criteria API
    • JPA에서 제공하는 표준 API
    • Querydsl이 나오기 전에는 동적 쿼리를 작성할 때 많이 사용되었지만, 코드가 너무 길고 가독성이 떨어지는 단점이 있음
  3. Native Query (SQL 직접 작성)
    • 복잡한 쿼리를 작성할 때 사용 가능
    • 데이터베이스 종속성이 높아지므로 유지보수 어려움
  4. JOOQ
    • Querydsl과 비슷한 기능을 제공하는 SQL 빌더
    • SQL 중심이라 JPA와의 연동보다는 직접 SQL을 다룰 때 유리