QueryDSL에 대해 알아보자

박대화·2023년 10월 26일

알아봅시다

목록 보기
1/2

QueryDSL

QueryDSL은 JPA에서 복잡한 쿼리나 동적쿼리를 작성할 때 도움을 주는 라이브러리입니다.

물론 JPQL을 사용하여 쿼리를 작성할수도 있지만 JPQL의 가장 큰 단점은 문자열을 통해 쿼리를 작성한다는 것입니다.
문자열을 통해 쿼리를 작성하게 되면 컴파일 단계에서 오류를 발견하기 어렵습니다.
또한 동적쿼리를 작성할 때도 if문으로 감싸져 있기 때문에 가독성이 좋지 않습니다.

그렇기 때문에 자바 코드를 사용하여 쉽고 간결하게 쿼리를 작성할 수 있는 QueryDSL을 사용했습니다.

QueryDSL을 사용하는 이유

  1. 형식적으로 안전하다.
    1. jpql이나 native sql은 String형식으로 쿼리를 작성하기 때문에 실제로 돌려봐야 오류를 확인할 수 있다.
    2. QueryDSL은 자동으로 엔티티의 쿼리타입을 만들어줘서 컴파일 과정에서 오류를 확인할 수 있다.
  2. 동적 쿼리
    1. 조건에 따라 동적으로 쿼리를 생성하기 쉽다.
  3. 가독성
    1. 메서드 체인 형식으로 되어 있어 코드가 읽기 쉽다.

QueryDSL 설정

QueryDSL 설정은 maven을 사용한다면 의존성만 추가해주면 되지만,

gradle로 설정하는 방법은 공식문서에 없어서 따로 설정해줘야 합니다.

일단 QueryDSL의 버전에 따라 설정 방법이 다릅니다.

4버전까지는 복잡하게 설정을 해야했지만

5버전부터는

// QueryDSL
implementation "com.querydsl:querydsl-jpa:5.0.0"
implementation "com.querydsl:querydsl-core:5.0.0"
annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jpa'
annotationProcessor "javax.persistence:javax.persistence-api"
annotationProcessor "javax.annotation:javax.annotation-api"

//dependencies 밖에 추가
sourceSets {
    main {
        java {
            srcDir("$projectDir/build/generated")
        }
    }
}

이렇게 추가만 하면 됩니다.

빌드를 하게 되면 build/generated 폴더 안에 entity가 작성되어 있는 폴더 안에 Q로 시작하는 entity가 생깁니다.

주의할 점은 clean하기 전에 빌드를 다시 한다면 이미 만들어진 entity라고 오류가 생깁니다.

이때는 clean을 먼저 하고 빌드를 하면 해결됩니다.

QueryDSL 사용법

먼저 import static com.conseller.conseller.entity.QAuction.*auction*; 처럼 Qentity의 객체를 가져옵니다.

private final JPAQueryFactory factory; factory 객체를 의존성 주입해줍니다.

기본적으로 factory 객체에 메서드 체이닝으로 쿼리문을 작성합니다.

selectFrom() : select와 from이 같다면 사용한다. Qentity를 넣어주면 됩니다.

select() : 찾고싶은 Q엔티티를 넣으면 엔티티가 반환되고, 원하는 컬럼만 찾고 싶다면 컬럼을 지정해 줄 수 있습니다.

QUser user = QUser.user;
List<Tuple> results = new JPAQuery<>(entityManager)
    .select(user.userIdx, user.userName)
    .from(user)
    .where(user.username.eq("대화"))
    .fetch();

컬럼을 지정해준다면 Tuple 객체 형태로 반환이 되고 get을 통해서 값을 확인할 수 있습니다.

for (Tuple row : results) {
    Long userIdx = row.get(user.userIdx);
    String userName = row.get(user.userName);
    // ... 이후의 처리
}

from() : 검색하고 싶은 Q엔티티를 넣습니다.

where() : 검색하고 싶은 조건을 BooleanExpression으로 추가합니다.

자주 사용하는 Boolean Expression 연산자

비교연산자

  1. eq() : 동일
  2. ne() : 동일하지 않음
  3. gt() : 초과
  4. goe() : 이상
  5. lt() : 미만
  6. loe() : 이하
  7. isNull() : null인지
  8. isNotNull() : null이 아닌지

논리연산자

  1. and() : and, 두 BooleanExpression 사이
  2. or() : or
  3. not() : not

문자열 연산

  1. startsWith() : 시작 문자열로 시작
  2. endsWith() : 특정 문자열로 끝
  3. contains() : 특정 문자열 포함
  4. like() : like 패턴 매치
  5. matches() : 정규표현식 매치

이 조건을 직접 where안에 넣어줄 수 있지만

함수의 형태로 만들어 값이 없다면 null을 반환하고, 값이 있다면 원하는 BooleanExpression을 반환해 동적 쿼리를 작성할 수 있습니다.

BooleanExpression이 null이라면 조건을 무시합니다.

private BooleanExpression eqSearch(String searchQuery) {
        if(!StringUtils.hasText(searchQuery)){
            return null;
        }

        return auction.gifticon.gifticonName.containsIgnoreCase(searchQuery);
    }

위와 같이 검색어가 없다면 null 있으면 검색어를 조건에 넣습니다.

orderBy() : 정렬 조건, OrderSpecifier 객체를 만들어 원하는 상태에 따라 정렬할 수 있도록 했습니다.

private OrderSpecifier orderSpecifier(Integer status) {
        if(status == 0) {
            return new OrderSpecifier(Order.DESC, auction.auctionStartDate);
        } else if (status == 1) {
            return new OrderSpecifier(Order.ASC, auction.gifticon.gifticonEndDate);
        } else if(status == 2) {
            return new OrderSpecifier(Order.ASC, auction.auctionHighestBid);
        } else  {
            return new OrderSpecifier(Order.ASC, auction.upperPrice);
        }
    }

groupBy() : 그룹화

having() : 그룹화 조건

offset() : pageable을 사용하기 위한 메서드, 시작하는 페이지를 정해줍니다.

limit() : 위에서부터 n개의 데이터를 가져옵니다.

집계함수

  1. sum() : 합계
  2. avg() : 평균
  3. max() : 최대값
  4. min() : 최소값
  5. count() : 행 수

조인 연산

  1. join() : inner join
  2. leftJoin()
  3. rightJoin()
  4. fullJoin()

쿼리 실행

  1. fetch() : 결과 리스트로 조회
  2. fetchOne() : 하나의 결과만 조회
  3. fetchFirst() : 첫 번째 결과만 조회
  4. fetchCount() : 결과 수 반환

이러한 메서드를 사용하여 쿼리문을 작성할 수 있습니다.

서브쿼리

서브쿼리를 만들 때에는 2가지 방법이 있는데

JPAExpressions로 만드는 방법과 JPASubQuery로 만드는 방법입니다.

JPAExpressions는 주로 간결하게 쿼리의 특정 부분에 서브쿼리를 삽입할 때 사용합니다.

JPASubQuery는 객체를 통해 서브쿼리를 생성하고, 좀 더 복잡한 쿼리문을 작성할 때 사용합니다.

결론

확실히 초기 설정만 잘 한다면 편리하고 좋은 라이브러리인 것 같다.

profile
잘하는 개발자(희망)

0개의 댓글