Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

동적쿼리 성능 최적화 : Builder , where 다중 파라미터 본문

인프런/[인프런] QueryDsl

동적쿼리 성능 최적화 : Builder , where 다중 파라미터

Seung__ 2021. 9. 4. 13:06

1. Builder


@Data
public class MemberTeamDto {

    private Long memberId;
    private String username;
    private int age;
    private Long teamId;
    private String teamName;

    public MemberTeamDto() {
    }

    @QueryProjection
    public MemberTeamDto(Long memberId, String username, int age, Long teamId, String teamName) {
        this.memberId = memberId;
        this.username = username;
        this.age = age;
        this.teamId = teamId;
        this.teamName = teamName;
    }
}
  • QMemberTeamDto 생성

 

  • Respository
    • 검색 조건인 MemberSearchConditon을 받아서 사용.
    • builder를 활용하여 동적쿼리 생성.
    • condition이 null로 올수도 있고, ""로 올 수 도 있어서 StringUtils.hasText를 사용.
    • Member는 name, MemberTeamDto에서는 username으로 필드명이 달라 .as로 지정.
    public List<MemberTeamDto> searchByBuilder(MemberSearchCondition condition){

        BooleanBuilder builder = new BooleanBuilder();
        if(StringUtils.hasText(condition.getUsername())){
            builder.and(member.username.eq(condition.getUsername()));
        }
        if(StringUtils.hasText(condition.getTeamName())){
            builder.and(team.name.eq(condition.getTeamName()));
        }
        if(condition.getAgeGoe() != null){
            builder.and(member.age.goe(condition.getAgeGoe()));
        }
        if(condition.getAgeLoe() != null){
            builder.and(member.age.goe(condition.getAgeLoe()));
        }


        return queryFactory
                .select(new QMemberTeamDto(
                        member.id.as("memberId"),
                        member.username,
                        member.age,
                        team.id.as("teamId"),
                        team.name.as("teamName")))
                .from(member)
                .leftJoin(member.team, team)
                .where(builder)
                .fetch();
    }
  • Test
    • 주의! condition이 없을 경우 모든 데이터를 다 가지고 온다. 
    • 성능 문제가 발생 할 수 있다.
    • limit 또는 paging처리가 같이 되어야 한다.
    @Test
    public void searchTest(){
        Team teamA = new Team("teamA");
        Team teamB = new Team("teamB");
        em.persist(teamA);
        em.persist(teamB);
        Member member1 = new Member("member1", 10, teamA);
        Member member2 = new Member("member2", 20, teamA);
        Member member3 = new Member("member3", 30, teamB);
        Member member4 = new Member("member4", 40, teamB);
        em.persist(member1);
        em.persist(member2);
        em.persist(member3);
        em.persist(member4);

        MemberSearchCondition condition = new MemberSearchCondition();
        condition.setAgeGoe(35);
        condition.setAgeLoe(40);
        condition.setTeamName("teamB");

        List<MemberTeamDto> result = memberJpaRepository.searchByBuilder(condition);
        assertThat(result).extracting("username").containsExactly("member4");
    }
   select
        member1.id as memberId,
        member1.username,
        member1.age,
        team.id as teamId,
        team.name as teamName 
    from
        Member member1   
    left join
        member1.team as team 
    where
        team.name = ?1 
        and member1.age >= ?2 
        and member1.age >= ?3

 

 

 

 

2. Where절 파라미터 사용 --> 깔끔, 가독성 좋음.


  • BooleanExpression으로 반환해야 재사용 및 조립(?) 가능.
  • projection을 변경해도 조건을 사용 가능.
    public List<MemberTeamDto> search(MemberSearchCondition condition){

        return queryFactory
                .select(new QMemberTeamDto(
                        member.id.as("memberId"),
                        member.username,
                        member.age,
                        team.id.as("teamId"),
                        team.name.as("teamName")))
                .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 hasText(username) ? member.username.eq(username) : null;
    }

    private BooleanExpression teamNameEq(String teamName) {
        return hasText(teamName) ? team.name.eq(teamName) : null; 
    }

    private BooleanExpression ageGoe(Integer ageGoe) {
        return ageGoe != null ? member.age.goe(ageGoe) : null;
    }

    private BooleanExpression ageLoe(Integer ageLoe) {
        return ageLoe != null ? member.age.loe(ageLoe) : null;
    }

 

 

3. GitHub : 210904 DynamicQuery


 

GitHub - bsh6463/Querydsl

Contribute to bsh6463/Querydsl development by creating an account on GitHub.

github.com

 

'인프런 > [인프런] QueryDsl' 카테고리의 다른 글

SpringDataJPA Repository, 사용자 정의 repository  (0) 2021.09.04
API 개발  (0) 2021.09.04
JPA Repository와 Querydsl  (0) 2021.09.04
SQL Function 호출  (0) 2021.09.04
벌크 연산  (0) 2021.09.04
Comments