-
Querydsl - where절을 이용한 동적 쿼리와 성능 최적화Spring/Querydsl 2022. 3. 26. 18:19728x90반응형
where절을 이용한 동적 쿼리와 성능 최적화
Member와 Team을 동적 쿼리를 이용하여 해당 조건에 맞는 데이터를 가져와 보자
1. 성능 최적화를 위해 DB에서 필요한 데이터만 가져올 수 있는 DTO를 생성한다.
@Data public class MemberTeamDto { private Long memberId; private String username; private int age; private Long teamId; private String teamName; public MemberTeamDto() { } @QueryProjection // (1) 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; } }
- (1) : Q-Type을 만들기위한 어노테이션
2. 동적 쿼리에 사용할 검색 조건 클래스 생성
@Data public class MemberSearchCondition { // 회원명, 팀명, 나이(ageGoe, ageLoe) private String username; private String teamName; private Integer ageGoe; private Integer ageLoe; }
3. Repository에 Where절을 이용한 동적 쿼리 메서드 구현
public List<MemberTeamDto> searchByWhere(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()), // (1) teamNameEq(condition.getTeamName()), ageGoe(condition.getAgeGoe()), ageLoe(condition.getAgeLoe()) ) .fetch(); } // BooleanExpression은 and, or 을 조합해서 새로운 BooleanExpression을 만들 수 있다. // 또한, 결과 값이 null일 경우 무시하기 때문에 npe를 방지할 수 있다 private BooleanExpression usernameEq(String username) { // (2) return StringUtils.hasText(username) ? member.username.eq(username) : null; } private BooleanExpression teamNameEq(String teamName) { // (3) return StringUtils.hasText(teamName) ? team.name.eq(teamName) : null; } private BooleanExpression ageGoe(Integer ageGoe) { // (4) return ageGoe != null ? member.age.goe(ageGoe) : null; } private BooleanExpression ageLoe(Integer ageLoe) { // (5) return ageLoe != null ? member.age.loe(ageLoe) : null; }
- (1) : where절의 특징으로 콤마(,)를 사용하면 and 조건으로 처리 된다. 만약 null이면 해당 조건은 제외 된다.
- (2) : username의 값이 존재하면 조건 추가, null or 빈문자("")일 경우 null 반환
- (3) : teamName의 값이 존재하면 조건 추가, null or 빈문자("")일 경우 null 반환
- (4) : ageGoe의 값이 존재하면 조건 추가, null 일 경우 null 반환
- (5) : ageLoe의 값이 존재하면 조건 추가, null 일 경우 null 반환
(2), (3), (4), (5)을 보면 반환 타입을 BooleanExpression을 사용한 것을 볼 수 있는데 Predicate를 사용하지 않은 이유는 BooleanExpression은 and, or을 조합하여 새로운 BooleanExpression을 만들 때 결과 값이 null일 경우 해당 조건은 제외시켜 NullPointrException을 방지할 수 있기 때문에 BooleanExpression을 사용한다.
4. 조회 테스트
@Test public void searchTest2() { 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> results = memberQuerydslRepository.searchByWhere(condition); }
Querydsl 쿼리와 JPQL 쿼리
/* select member1.id, member1.username, member1.age, team.id, team.name from Member member1 left join member1.team as team where team.name = ?1 and member1.age >= ?2 and member1.age <= ?3 */ select member0_.member_id as col_0_0_, member0_.username as col_1_0_, member0_.age as col_2_0_, team1_.team_id as col_3_0_, team1_.name as col_4_0_ from member member0_ left outer join team team1_ on member0_.team_id=team1_.team_id where team1_.name=? and member0_.age>=? and member0_.age<=?
위 쿼리를 보면 MemberSearchCondition의 username값이 null이므로 검색조건에 제외된 것을 볼 수 있다. 이렇듯 null
값이면 검색조건에 제외, null이 아닌 데이터 값이 있을 경우 검색 조건에 추가되는 동적 쿼리를 사용할 수 있다.
조회 API 컨트롤러 예시
@RestController @RequiredArgsConstructor public class MemberController { private final MemberQuerydslRepository memberQuerydslRepository; @GetMapping("/v1/members") public List<MemberTeamDto> searchMemberV1(MemberSearchCondition condition){ return memberJpaRepository.search(condition); } }
요청 예시
- localhost:8080/v1/members?teamName=team&ageGoe=31&ageLoe=35
파라미터로 검색조건을 넘겨주면 된다.
참고
BooleanBuilder와 BooleanExpression728x90반응형'Spring > Querydsl' 카테고리의 다른 글
Querydsl - Spring Data JPA에서 제공하는 페이징 활용 (3) 2022.03.26 Querydsl - Spring Data JPA와 QueryDSL (0) 2022.03.26 Querydsl - BooleanBuilder를 사용한 동적 쿼리와 성능 최적화 (0) 2022.03.26 Querydsl - Repository에서 Querydsl 사용하기 (0) 2022.03.26 Querydsl - 수정, 삭제 벌크 연산 (0) 2022.03.25