이 영역을 누르면 첫 페이지로 이동
시간의화살 블로그의 첫 페이지로 이동

시간의화살

페이지 맨 위로 올라가기

시간의화살

행복하세요

[QueryDSL] 활용 (Spring Data JPA + QueryDSL)

  • 2023.01.11 17:46
  • Spring/QueryDSL

 

 

 

웬만한 기능은 Spring Data JPA가 제공해주고, 동적 쿼리 등 복잡한 구현이 필요할 때 QueryDSL 기술을 사용한다.

 

따로 Repository를 하나 만들어서 기능을 구현하자.

 

 

 

 

MemberRepositoryCustom을 인터페이스로 만들고 구현할 기능을 선언한 후 MemerRepositoryImpl에 기능을 구현한다.

 

 

public class MemberRepositoryImpl implements MemberRepositoryCustom {
    private final JPAQueryFactory queryFactory;
    
    public MemberRepositoryImpl(EntityManager em) {
        this.queryFactory = new JPAQueryFactory(em);
    }
    
    @Override
    public List<MemberTeamDto> search(MemberSearchCondition condition) {
        return queryFactory
                .select(new QMemberTeamDto(
                        member.id,
                        member.username,
                        member.age,
                        team.id,
                        team.name))
                .from(member)
                .leftJoin(member.team, team)
                .where(usernameEq(condition.getUsername()),
                        teamNameEq(condition.getTeamName()),
                        ageGoe(condition.getAgeGoe()),
                        ageLoe(condition.getAgeLoe()))
                .fetch();
    }
    private BooleanExpression usernameEq(String username) {
        return isEmpty(username) ? null : member.username.eq(username);
    }
    private BooleanExpression teamNameEq(String teamName) {
        return isEmpty(teamName) ? null : team.name.eq(teamName);
    }
    private BooleanExpression ageGoe(Integer ageGoe) {
        return ageGoe == null ? null : member.age.goe(ageGoe);
    }
    private BooleanExpression ageLoe(Integer ageLoe) {
        return ageLoe == null ? null : member.age.loe(ageLoe);
    }
}

 

 

구현은 JPA를 사용할 때와 동일하게 진행한다. (where 다중 파라미터 사용)

 

이렇게 Custom Repository를 따로 만드는것도 괜찮지만, 프로젝트 규모가 커지고 너무 복잡해진다 싶으면 조회만을 위한 클래스를 새로 만들어서 분리하는 방식의 설계도 고려해보자.

 

 

 

Spring Data JPA 가 제공하는 페이징 처리도 QueryDSL 과 결합해서 사용할 수 있다.

 

 

 

 

우선 Custom Repository에 페이징 관련 메서드를 추가해주자.

 

 

    @Override
    public Page<MemberTeamDto> searchPageSimple(MemberSearchCondition condition, Pageable pageable) {
        QueryResults<MemberTeamDto> results = queryFactory
                .select(new QMemberTeamDto(
                        member.id,
                        member.username,
                        member.age,
                        team.id,
                        team.name))
                .from(member)
                .leftJoin(member.team, team)
                .where(usernameEq(condition.getUsername()),
                        teamNameEq(condition.getTeamName()),
                        ageGoe(condition.getAgeGoe()),
                        ageLoe(condition.getAgeLoe()))
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetchResults();

        List<MemberTeamDto> content = results.getResults();

        long total = results.getTotal();

        return new PageImpl<>(content, pageable, total);
    }

 

 

 

fetch를 사용하면 데이터를 바로 가져온다. 따라서 fetchResults를 사용해 count 쿼리를 추가로 날리자. (fetch와 fetchCount를 분리해서 사용하는 편이 더 좋은 방법이다)

리스트와 총 개수를 사용해 Page 객체의 구현체를 만들어서 반환한다.

 

 

    @Override
    public Page<MemberTeamDto> searchPageComplex(MemberSearchCondition condition, Pageable pageable) {
        List<MemberTeamDto> content = queryFactory
                .select(new QMemberTeamDto(
                        member.id,
                        member.username,
                        member.age,
                        team.id,
                        team.name))
                .from(member)
                .leftJoin(member.team, team)
                .where(usernameEq(condition.getUsername()),
                        teamNameEq(condition.getTeamName()),
                        ageGoe(condition.getAgeGoe()),
                        ageLoe(condition.getAgeLoe()))
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();

        JPAQuery<Member> countQuery = queryFactory
                .select(member)
                .from(member)
                .leftJoin(member.team, team)
                .where(usernameEq(condition.getUsername()),
                        teamNameEq(condition.getTeamName()),
                        ageGoe(condition.getAgeGoe()),
                        ageLoe(condition.getAgeLoe()));

        return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchCount);
    }

 

 

좀 더 최적화 해 보자.

 

count 쿼리가 필요하지 않은 경우 굳이 쿼리를 날리지 않아도 되지 않나?

컨텐츠 크기가 페이지 크기보다 작으면? (페이지는 100개인데 컨텐츠가 3개)

 

굳이 count 쿼리를 날리지 않고 컨텐츠의 크기로 totalCount를 설정해도 상관없다.

 

또한 마지막 페이지에서도 count 쿼리를 날리지 않아도 괜찮다. (offset + 컨텐츠 크기가 totalCount가 된다)

 

Spring Data JPA가 제공하는 기능이니 웬만하면 사용해서 성능을 최적화하자.

 

 

 

 

 

 

반응형
저작자표시 (새창열림)

'Spring > QueryDSL' 카테고리의 다른 글

[QueryDSL] 활용 (JPA + QueryDSL)  (0) 2023.01.11
[QueryDSL] 중급 문법  (0) 2023.01.10
[QueryDSL] 기본 문법  (0) 2023.01.09

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [QueryDSL] 활용 (JPA + QueryDSL)

    [QueryDSL] 활용 (JPA + QueryDSL)

    2023.01.11
  • [QueryDSL] 중급 문법

    [QueryDSL] 중급 문법

    2023.01.10
  • [QueryDSL] 기본 문법

    [QueryDSL] 기본 문법

    2023.01.09
다른 글 더 둘러보기

정보

시간의화살 블로그의 첫 페이지로 이동

시간의화살

  • 시간의화살의 첫 페이지로 이동

검색

방문자

  • 전체 방문자
  • 오늘
  • 어제

카테고리

  • 분류 전체보기 (610)
    • Algorithm (205)
      • Data Structure (5)
      • Theory && Tip (33)
      • Baekjoon (166)
      • ALGOSPOT (1)
    • Spring (123)
      • Spring (28)
      • Spring Web MVC (20)
      • Spring Database (14)
      • Spring Boot (6)
      • Spring 3.1 (11)
      • Spring Batch (6)
      • Spring Security (16)
      • JPA (12)
      • Spring Data JPA (5)
      • QueryDSL (4)
      • eGovFramework (1)
    • Programming Language (74)
      • Java (19)
      • JavaScript (15)
      • C (25)
      • C++ (12)
      • Python (1)
      • PHP (2)
    • Computer Science (69)
      • Operating System (18)
      • Computer Network (17)
      • System Programming (22)
      • Universial Programming Lang.. (8)
      • Computer Architecture (4)
    • Database (21)
      • Database (7)
      • MySQL (3)
      • Oracle (3)
      • Redis (5)
      • Elasticsearch (3)
    • DevOps (20)
      • Docker && Kubernetes (8)
      • Jenkins (4)
      • Github Actions (0)
      • Amazon Web Service (8)
    • Machine Learning (28)
      • AI Introduction (28)
    • Mobile (28)
      • Android (21)
      • Flutter (7)
    • Solutions (14)
    • Life Logs (3)
    • 낙서장 (25)

최근 글

나의 외부 링크

메뉴

  • 홈

정보

13months의 시간의화살

시간의화살

13months

블로그 구독하기

  • 구독하기
  • RSS 피드

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © 13months.

티스토리툴바