QueryDSL

조승빈·2025년 1월 7일

Spring DB

목록 보기
6/8

기존 방식의 한계

  • 문자열을 합쳐서 쿼리를 구성하는 경우 실행하기 전까지 쿼리의 작동 여부를 알 수 없음.

  • Type-Check 불가능: 런타임 에러가 발생할 가능성 증가.

QueryDSL의 장점

  • SQL이나 JPQL을 클래스와 타입처럼 자바 코드로 작성할 수 있음.

  • Type-Safe: 컴파일 시점에 문법 에러를 체크 가능.

  • 복잡한 조회와 동적 쿼리를 안전하게 작성할 수 있음.

예시 코드: 기존 JPQL vs QueryDSL

JPQL 예시 (문자열 사용):

String jpql = "SELECT m FROM Member m WHERE m.username = :username";
TypedQuery<Member> query = em.createQuery(jpql, Member.class);
query.setParameter("username", "john");
List<Member> result = query.getResultList();

문자열로 작성되기 때문에 컴파일 시점에 문법 오류를 체크할 수 없음.

QueryDSL 예시 (Type-Safe 코드):

// Q 클래스 생성 (QueryDSL이 제공하는 메타모델 클래스)
QMember member = QMember.member;

// QueryDSL로 작성된 타입 안전 쿼리
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
List<Member> result = queryFactory
    .selectFrom(member)
    .where(member.username.eq("john"))
    .fetch();

QMemberQueryDSL이 생성한 클래스이며, member.username.eq("john")처럼 필드를 타입 안전하게 참조 가능.

Type-Safe : 코드에서 컴파일 단계에서 오류를 확인할 수 있는 특성.

Spring Data의 단점과 QueryDSL의 보완

Spring Data JPA는 기본 CRUD 메서드는 자동 생성하지만, 복잡한 조회 쿼리는 직접 작성해야 함.

QueryDSL은 복잡한 조건이나 동적 쿼리를 깔끔하고 안전하게 작성할 수 있도록 도와줌.

복잡한 동적 쿼리 예시

// 검색 조건 동적 처리
BooleanBuilder builder = new BooleanBuilder();
if (username != null) {
    builder.and(member.username.eq(username));
}
if (age != null) {
    builder.and(member.age.goe(age));
}

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

BooleanBuilder를 사용하여 조건을 유연하게 추가 가능.

조건이 많아질수록 QueryDSL의 장점이 극대화됨.

Q파일?

QueryDSL에서 쿼리를 작성할 때 사용하는 자동 생성 클래스이다.

  • QueryDSL을 사용하면 데이터베이스의 테이블을 Java코드로 다룰 수 있다. 이때 테이블의 컬럼들을 객체의 필드처럼 사용할 수 있게 해주는 클래스가 Q파일이다.
  • Q파일은 컴파일할 때 자동으로 생성되며, 사용자가 직접 작성할 필요가 없다.

Member 예시

Member 엔티티 예시

@Entity
public class Member {
    @Id
    private Long id;
    private String username;
    private int age;
}

자동 생성된 QMember 클래스

public class QMember extends EntityPathBase<Member> {
    public static final QMember member = new QMember("member");

    public final StringPath username = createString("username");
    public final NumberPath<Integer> age = createNumber("age", Integer.class);

    public QMember(String variable) {
        super(Member.class, PathMetadataFactory.forVariable(variable));
    }
}
  • QMember에서 usernameage는 타입이 명확한 필드로 정의되어 있다.
  • username은 StringPath로 정의되어 있으며, member.username.eq("jhon")처럼 사용하면 된다.

ORM과 QueryDSL의 차이점과 역할

ORM : JPAORM 매핑을 통해 데이터베이스의 테이블과 Java 객체를 연결한다.
-> 데이터베이스에 member 테이블이 있다고 가정하면, ORM이 Member 객체와 member 테이블을 매핑한다.

QueryDSL : ORM 매핑 정보를 사용하여 type-safe 쿼리를 작성한다.

  • QueryDSLJPA외에도 SQL, MongoDB 등을 위한 모듈도 제공한다. 따라서 JPA가 아닌 다른 데이터 접근 기술을 활용하여 쿼리를 작성할 수 있다.
  • 따라서 QueryDSLORM(JPA)와 결합하면 좋은 성능을 보여주지만, 반드시 ORM이 필수가 되는 것은 아니다.

ORM이 데이터 매핑을 담당하고, QueryDSL은 타입 안전한 쿼리를 작성하게 해주는 도구로 서로 보완적인 역할을 한다.


데이터 접근 기술 정리

profile
평범

0개의 댓글