본문 바로가기
프로그래밍/Spring

querydsl Pageable(), offset, limit을 이용한 페이징 방법

by Mr-후 2023. 7. 28.
반응형

오늘 QueryDSL을 이용한 페이징을 만드는 일을 했는데, 대충 대충 눈으로만 익혔던 지식의 한계를 느끼며 삽질을 좀 했지만 

나름 재미는 있었다. 

 

애초에 '회의록'를 조회하는 조건은 날짜, 검색어, 사용자 등으로 검색한 결과를 JPA Repository를 이용해 페이징을 했었다. 

'회의록'에 참석한 사용자의 경우에도 회의록을 조회할 경우 자기도 포함된 회의록이 나오도록 수정해달라는 요청을 받았다. 

애초, 조인 없이 단일 테이블 조회로 만들어진 기능을 조인을 넣어 현재 로그인 한 사용자가 참석한 회의록이 있을 때도 나오도록 수정하면서 JPA Repository의 pageable을 통한 것이 아니라 QueryResults를 통해 offset과  limit를 이용해 페이징되도록 수정하였다. 

 

QueryDSL을 통해 조인하는 것도 익숙지 않으며, 페이징도 익숙하지 않다.

뭐 스프링 부트가 다 익숙하지 않은데, 뾰족한 수가 있나 ㅎㅎ 

 

여튼, '회의록' 테이블과 '회의록 참석자' 테이블을 조인한다. '회의록 참석자' 테이블은 '회의록' 테이블의 아이디를 참조하고 있으며 회원의 아이디를 가지고 있는 상태이다. 

 

    @Override
    public Page<Conference> findByAllConference(User user, Filter filter, ConferenceStatus conferenceStatus) {
        QConference conference = QConference.conference;
        QConferenceUser conferenceUser = QConferenceUser.conferenceUser;

        QueryResults queryResults = jpaQueryFactory.select(conference)
                .from(conference)
                .join(conferenceUser).on(conference.id.eq(conferenceUser.relativeConference.id)).fetchJoin()
                .where(conference.relativeUser.id.eq(user.getId()).or(conferenceUser.relativeUser.id.eq(user.getId())))
                .where(ConferenceApiPredicate.getInstance()
                        .startDate(filter.getStartDate())
                        .endDate(filter.getEndDate())
                        .search(filter.getQuery())
                        .status(conferenceStatus).values())
                .orderBy(conference.createdDate.desc())
                .offset(filter.getPageable().getOffset())
                .limit(filter.getPageable().getPageSize())
                .fetchResults();

        long total = queryResults.getTotal();
        return new PageImpl<>(queryResults.getResults(), filter.getPageable(), total);
    }

 

페이징이 되는 원리에 대해서 모르는 것은 아니나, offset에 대한 이해를 잘모르고 사용하였다. 

offset은 리스트의 몇번째 부터, limit까지 제한하는 역할을 한다. 

즉 mysql에서 

select * from '회의록' limit 10, 10 // 앞에 10이 offset, 뒤에 10이 limit이다. 10번째부터 10개를 가져오도록 하는 것인데 

변수로 받는 pageNo와 pageSize 에 대한 정리가 필요했다. 

if (pageNo == 1 || pageNo < 1) {
    pageNo = 0;
} else {
    pageNo--;
}

Pageable pageable = PageRequest.of(pageNo, pageSize, Sort.Direction.DESC, "createdDate");
Filter filter = new Filter(pageable, query, startDate, endDate);
Page<GetConferenceResBody> page = conferenceService.getConference(filter, conferenceStatus, loginId);

PageRequest.of()를 이용해 pageNo, pageSize를 넣어 pageable을 만들때 내부적으로 getter만 허용하는 getOffset()이라는 함수가 만들어지는데 이 때 offset계산을 pageNo * pageSize로 값을 할당해 둔다. 

즉, 1페이지의 리스트를 구할 때 pageNo의 값은 0이 되어야 하며, 2페이지의 리스트를 구할 때는 10부터 ~20까지 가져와야하므로 

pageNo의 값이 2로 온다면 -1를 해주어 1 * 10이 offset으로 할당되도록 해주면 된다. 

클라이언트에서 0부터 보낸다면 저런 짓은 필요가 없겠지만... 

저렇게 정리를 했으면 금방 끝났을 일인데, 별짓다하면서 공부 참 많이 했다. 

 

결국은 offset과 limit를 이용해서 지정된 범위의 리스트를 가져오게 만드는 것이 성능에도 더 많은 도움이 될 것이라고 생각이 된다. 

참 편하고 좋은 기술인데... 

옛날 asp로 게시판 짜든 시절이 생각나기도 한다. ^^ 

 

 

반응형