먼저, 간단하게 QueryDSL에서 제공해 주는 기능.
@Override
public Page<MemberTeamDto> searchPageSimple(MemberSearchCondition condition, Pageable pageable) {
QueryResults<MemberTeamDto> result = query.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 = result.getResults();
long total = result.getTotal();
return new PageImpl<>(content, pageable, total);
}
이나,
현재 deprecated 된 기능이다.
이유는 카운트 쿼리가 제대로 만들어지지 않을 수도 있기 때문.
JPQL에서는 본래 서브쿼리를 지원하지 않기 때문이라고 한다.
https://qwefdg3.tistory.com/924
그리고, count쿼리는 생각보다 자원이 많이 든다. 전체 데이터를 조회해야 하기 때문.
그런데 저렇게 join이나 where 더덕더덕 붙인거에, 카운트쿼리로 나가는 거다.
하다보면 카운트쿼리는 저런 조건들을 더덕더덕 붙이지 않아도 될 때가 있다.
그래서, 카운트쿼리는 개발자가 직접 짜도록 유도하기 위해 이렇게 하는 것 같다.
fetchResults()는 fetchCount()도 같이 나가는데, 마찬가지인 이유로 fetchCount()도 deprecated 되었다.
그래서 이제 방법은, 사용자가 직접 콘텐츠와 카운트쿼리로 값을 가져온 다음, 페이지 객체로 만드는 것이다.
@Override
public Page<MemberTeamDto> searchPageComplex(MemberSearchCondition condition, Pageable pageable) {
List<MemberTeamDto> result = query.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<Long> countQuery= query.select(member.count()).from(member).leftJoin(member.team, team)
.where(
usernameEq(condition.getUsername()),
teamNameEq(condition.getTeamName()),
ageGoe(condition.getAgeGoe()),
ageLoe(condition.getAgeLoe())
);
return PageableExecutionUtils.getPage(result, pageable, countQuery::fetchOne);
}
위에 콘텐츠 가져오는 것은 같다.
그런데, 보면 카운트쿼리를 값이 아닌 람다식으로,
페이징 유틸리티
저 PageableExecuteionUtils.getPage() 라는 것에 주고 있다.
이유가 있다.
먼저 최적화를 위해서다.
먼저, 0번째 페이지를 가져왔는데 pageSize보다 콘텐츠의 사이즈가 작을 경우, 그 콘텐츠가 최대 갯수라는 소리이다.
그리고, 마찬가지로 마지막 페이지일 경우, 마지막 페이지의 콘텐츠 개수가 페이지 사이즈보다 작을 경우, 그것 또한 최대 사이즈를 구할 수 있다.
offset + 현재페이지 콘텐츠 사이즈
그리고, 카운트가 필요하기 전 까지 실행하지 않을 수 있다.
마치 엔티티의 지연로딩 처럼.
그리고,
countQuery::fetchOne 저게
() -> countQuery.fetchOne() 이거랑 같은데,
이상하게 람다는 경고를 주고 더블콜론은 경고를 주지 않는다.
질문해 봤다.
https://www.inflearn.com/questions/1091891
더블콜론은 여러 사용법이 있는데,
1. 정적메소드 참조
클래스이름::정적메소드
2. 객체의 메소드 참조
객체::그객체의메소드
3. 들어올 객체의 메소드 참조
클래스명::메소드명
이거는 람다식으로 들어올 인자의 메소드를 쓸 수 있는거.
그러므로, 클래스가 맞아야 함.
예를 들어 String::toUpperCase
풀자면 (str -> str.toUpperCase())
결국엔 걔가 가지고 있는 메소드를 쓰는거임.
4. 생성자 참조
클래스명::new
'스프링데이터 + JPA > QueryDSL' 카테고리의 다른 글
35. 스프링 데이터 JPA가 제동하는 QueryDSL 기능 (0) | 2023.12.04 |
---|---|
34. QueryDSL 페이지 컨트롤러 (0) | 2023.12.04 |
32. 사용자 정의 리포지토리 (0) | 2023.12.04 |
31. 순수 JPA -> 스프링 데이터 JPA (0) | 2023.12.04 |
30. 조회 API 컨트롤러 만들기 (0) | 2023.12.03 |