- 현재 커뮤니티 서비스를 개발중 페이징을 기존 offset방식으로 생각하고있었다.
- 게시글 리스트를 조회할 때 무한 스크롤방식으로 진행하고 싶다고 요구
- ★ 위 요구사항을 충족시킬 방법을 찾아보다 과연 기존 offset방식의 페이징이 커뮤니티 서비스에 적합한가?라는 의문이 생겼다.
- ★ 커뮤니티 서비스는 데이터의 C/U/D가 매우 빈번하다!
-10시 30분에 생성된 게시글 30개 A
-10시 31분에 생성된 게시글 30개 B
-10시 32분에 생성된 게시글 30개 C가 있을 때
- 최신순으로 B를 가져온 후 커서를 내려서 다음 A를 가져오기 직전, 10시 32분에 게시글 C가 생성되었다면?
- 기존 offset방식이라면 맨 앞에 30개의 게시글이 새로 추가되었고 이에따라 30개마다 한 페이지씩 밀리며 따라서 위 상황에서 다음걸 가져올 때 또다시 B를 갖고 오게 될거라 생각. -> 해결방안이 필요
방안:
No offset paging
기본적으로 나중에 생긴 article이 더 큰 ID를 가짐.
10시 31분에 생성된 게시글 30개 B
10시 30분에 생성된 게시글 30개 A가 있을 때
최신순이니까 먼저 B를 가져오고 이 후 다음거를 가져오기 위해 스크롤을 내릴 때 10시 32분에 게시글 C가 생성됨.
여기서 우리는 aritcle을 id기준 desc로 정렬한 후 마지막으로 전달받은 B의 id보다 작은애들 중 최신 30개를 가져오면 A를 가져오는것
가장 최근에 생긴 C는 B의 마지막 article Id보다 크니까 자동으로 무시
적용
만약 맨 처음이라면 lastArticleId가 없을테고 이를위해 동적쿼리를 사용
null을 반환해줌으로써 조건이 없어지도록
만약 lastArticleId가 전달되었다면 해당 id를 기준으로 더 작은 id를 가진 article(더 이전에 만들어진 게시글)을 최신순으로 30개씩 가져온다. // 아래로 스크롤 했을 때
class ArticleRepositoryExtensionImpl(
val queryFactory:JPAQueryFactory
) : ArticleRepositoryExtension {
override fun getPaging(lastArticleId: Long?,keyword:String): List<Article> {
return queryFactory.selectFrom(article)
.where(
article.title.containsIgnoreCase(keyword),
checkArticleId(article.id, lastArticleId)
)
.orderBy(article.createdAt.desc())
.limit(30)
.fetch()
}
private fun checkArticleId(articleId: NumberPath<Long>, lastArticleId: Long?): BooleanExpression? {
if (lastArticleId == null) {
return null
} else {
return articleId.lt(lastArticleId) // lt == lower than
}
}
}
개요 :
방안:
적용
만약 lastArticleId가 전달되었다면 해당 id를 기준으로 더 작은 id를 가진 article(더 이전에 만들어진 게시글)을 최신순으로 30개씩 가져온다. // 아래로 스크롤 했을 때