[Spring] Query DSL - 기본 문법

Kyungmin·2024년 4월 8일
0

Spring

목록 보기
8/39

📝 QueryDSL 김영한님의 강의 를 바탕으로 공부하였습니다.

Query DSL

  • 하이버네이트 쿼리 언어의 쿼리를 타입에 안전하게 생성 및 관리해주는 프레임 워크
  • Query DSL 은 정적 타입을 이용하여 SQL 과 같은 쿼리를 생성할 수 있게 해준다.
  • 자바 백엔드 기술은 Spring Boot와 Spring Data JPA를 함께 사용한다. 하지만, 복잡한 쿼리, 동적 쿼리를 구현하는 데 있어 한계가 있다. 이러한 문제점을 해결할 수 있는 것이 QueryDSL이다.
  • QueryDSL이 등장하기 이전에는 Mybatis, JPQL, Criteria 등 문자열 형태로 쿼리문을 작성하여 컴파일 시에 오류를 발견하는 것이 불가능했다.
  • 하지만, QueryDSL은 자바 코드로 SQL 문을 작성할 수 있어 컴파일 시에 오류를 발생하여 잘못된 쿼리가 실행되는 것을 방지 할 수 있다.

Query DSL 의 장점

Querydsl을 사용하여 Dto 리스트를 직접 반환하는 방식은 데이터베이스로부터 데이터를 조회할 때 필요한 정보를 한 번의 쿼리로 완전히 가져오기 때문에, stream().map() 과정을 거치지 않아도 된다. 즉, Querydsl 쿼리에서 Projections.fields() (또는 다른 Projections 방법)를 사용함으로써 필요한 데이터를 바로 DTO 형태로 매핑하고, 추가적인 변환 과정 없이 바로 결과를 반환할 수 있다.

👉 Querydsl 방식의 장점

1. 성능 최적화: 한 번의 쿼리로 필요한 모든 데이터를 가져올 수 있으므로, 네트워크 라운드 트립을 줄이고, 전체적인 성능을 향상시킬 수 있습니다. stream().map() 과정에서 발생할 수 있는 추가적인 쿼리 실행(예: postService.getPostId(bookmark.getPost().getId()) 호출)이 필요 없습니다.
2. 코드 간소화: 데이터를 가져온 후 Java 스트림 API를 사용하여 객체를 변환하는 추가적인 작업이 없으므로, 코드가 더 간결하고 명확해집니다. 이는 유지보수성을 높이는 데 도움이 됩니다.
3. 타입 안전성: Querydsl을 사용하면, 컴파일 시점에 쿼리의 타입 안전성을 검증할 수 있습니다. 즉, 개발 중에 쿼리 관련 실수를 더 쉽게 발견하고 수정할 수 있습니다.

Query DSL 과 JPQL 의 차이?

  • JPQL
  1. 문자로 되어 있다.(실행 시점 오류, 런타임 시점 오류)
  2. 파라미터 바인딩(직접)
  • QueryDSL
  1. 자바 코드로 되어 있다.(컴파일 시점 오류)
  2. 파라미터 바인딩 자동 처리

QClass(큐 클래스)

  • 엔티티 클래스의 메타 정보를 담고 있는 클래스로, Querydsl은 이를 이용하여 타입 안정성(Type safe)을 보장하면서 쿼리를 작성할 수 있게 된다.
  • QClass는 엔티티 클래스와 대응되며  엔티티의 속성을 나타내고 있다. 이러한 QClass를 사용하여 쿼리를 작성하면 엔티티 속성을 직접 참조하고 조합하여 쿼리를 구성할 수 있다. QClass를 사용하면 컴파일 시점에 오류를 확인할 수 있고, IDE의 자동완성 기능을 활용하여 쿼리 작성을 보다 편리하게 할 수 있다.

✅ QClass 의 사용 목적

QueryDSL의 목적은 JPQL 생성이다. 개발자는 QueryDSL이 JPQL을 생성할 수 있도록 필요한 데이터를 세팅하여 전달해야 한다. 일단 Entity 정보가 필요하다. 그러나 Entity는 JPA프레임워크에서 지원하는 모듈이다. QueryDSL은 쿼리생성에 특화된 프레임워크로, JPA 프레임워크와 분리되어 있다. 그러므로 다른 프레임워크의 모듈을 그대로 사용하면 JPA프레임워크에 종속되어버린다. 이런 현상을 막고자, QueryDSL은 Entity 정보를 담은 Q타입클래스 를 사용한다.

QClass 를 엔티티 클래스 대신 사용하는 이유?

  1. QClass는 엔티티 속성을 정적인 방식으로 표현하므로 IDE의 자동 완성 기능을 활용할 수 있고, 속성 이름을 직접 기억하거나 확인하지 않아도 된다는 장점을 가지고 있다. 
  2. QClass는 엔티티 속성의 타입을 정확하게 표현하므로, 타입에 맞지 않는 연산이나 비교를 시도하면 컴파일러가 오류를 감지할 수 있다.

✅ 기본 Q-TYPE 활용

Q클래스 인스턴스를 사용하는 2가지 방법

QMember qMember = new QMember("m"); //별칭 직접 지정 
QMember qMember = QMember.member; //기본 인스턴스 사용

기본 인스턴스를 static import와 함께 사용

import static study.querydsl.entity.QMember.*;



 @Test
 public void startQuerydsl() {
 
//member1을 찾아라.
Member findMember = queryFactory
             .select(member)
             .from(member)
             .where(member.username.eq("member1"))
             .fetchOne();
     assertThat(findMember.getUsername()).isEqualTo("member1");
 }

결과 조회

  • fetch() : 리스트 조회, 데이터 없으면 빈 리스트 반환 `
  • fetchOne() : 단 건 조회
    - 결과가 없으면 : null
    - 결과가 둘 이상이면 :com.querydsl.core.NonUniqueResultException
  • fetchFirst() : limit(1).fetchOne()
  • fetchResults() : 페이징 정보 포함, total count 쿼리 추가 실행
  • fetchCount() : count 쿼리로 변경해서 count 수 조회
//List
List<Member> fetch = queryFactory
        .selectFrom(member)
.fetch();

//단 건
Member findMember1 = queryFactory
        .selectFrom(member)
        .fetchOne();
        
//처음 한 건 조회
Member findMember2 = queryFactory
        .selectFrom(member)
        .fetchFirst(); 

간단한 페이징

@Test
public void paging1() {
 List<Member> result = queryFactory
 	.selectFrom(member)
 	.orderBy(member.username.desc())	// username 기준 내림차순 정렬
 	.offset(0) // 0부터 시작(zero index)
 	.limit(5) // 최대 5건 조회
 	.fetch();
    
 assertThat(result.size()).isEqualTo(5);
}

참고자료

profile
Backend Developer

0개의 댓글

관련 채용 정보