๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring

[JPA] ์ปค์„œ ๊ธฐ๋ฐ˜ pagenation ๊ตฌํ˜„ํ•˜๊ธฐ

by young-ji 2023. 3. 1.

์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜

Cursor ๊ฐœ๋…์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ์‘๋‹ตํ•ด์ค€ ๋งˆ์ง€๋ง‰ ๋ฐ์ดํ„ฐ ๊ธฐ์ค€์œผ๋กœ ๋‹ค์Œ n๊ฐœ ์š”์ฒญ/์‘๋‹ต

 

offset ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค๋ฉด

SELECT * FROM items WHERE ์กฐ๊ฑด๋ฌธ ORDER BY id DESC OFFSET ํŽ˜์ด์ง€๋ฒˆํ˜ธ LIMIT ํŽ˜์ด์ง€์‚ฌ์ด์ฆˆ

cursor ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

SELECT * FROM items WHERE ์กฐ๊ฑด๋ฌธ AND id < ๋งˆ์ง€๋ง‰์กฐํšŒ_id ORDER BY id DESC LIMIT ํŽ˜์ด์ง€์‚ฌ์ด์ฆˆ

์ง์ „ ์กฐํšŒ ๊ฒฐ๊ณผ์˜ ๋งˆ์ง€๋ง‰ ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋กœ ๋“ค์–ด๊ฐ€๋Š”๋ฐ SQL ํ‚ค์›Œ๋“œ๊ฐ€ ์•„๋‹Œ ๊ณ ์ •๋œ ์กฐ๊ฑด๋ฌธ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ๋•Œ๋ฌธ์— ์ •์  ์ฟผ๋ฆฌ๋กœ์„œ์˜ ํ•œ๊ณ„๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค. (๋ฌผ๋ก  ๋™์  ์ฟผ๋ฆฌ์ธ QueryDSL์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.)

 

 

controller

/**
 * ๊ฒŒ์‹œ๋ฌผ page ์กฐํšŒ
 *
 * @param cursorId
 * @return CursorResult<PostDto>
 */
@GetMapping(produces = APPLICATION_JSON_VALUE)
public ApiResponse<CursorResult<PostDTO.Response>> getPosts(@RequestParam("cursorId")Interger cursorId) {
    CursorResult<PostDTO.Response> page = postService.findAll(PageRequest.of(0,10), cursorId);
    return ApiResponse.ok(page);
}

PageRequest.of()์˜ ์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๋ฌด์กฐ๊ฑด 0์œผ๋กœ, ์ฆ‰ ์ตœ์ดˆ์˜ ํŽ˜์ด์ง€๋กœ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค.

 

public class CursorResult<T> {
    private List<T> values;
    private Boolean hasNext; // ๋‹ค์Œ ํŽ˜์ด์ง€๊ฐ€ ์žˆ๋Š”์ง€ ํ•จ๊ป˜ ์•Œ๋ ค์ค€๋‹ค.

    public CursorResult(List<T> values, Boolean hasNext) {
        this.values = values;
        this.hasNext = hasNext;
    }
}

 

repository

public interface PostJpaRepository extends JpaRepository<Post, Long> {

    Slice<Post> findAllByIdLessThanOrderByIdDesc(Long id, Pageable pageable);

    Slice<Post> findAllByOrderByIdDesc(Pageable pageable); // ์ตœ์ดˆ์ผ ๊ฒฝ์šฐ, cursorId๊ฐ€ null ์ผ ๊ฒฝ์šฐ
}

์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ํ˜ธ์ถœ ๊ธฐ์ค€์ด ํ•˜๋‚˜๋ผ๋ฉด ๋ฌธ์ œ ์—†๊ฒ ์ง€๋งŒ ์ •๋ ฌ ์กฐ๊ฑด์ด๋‚˜ ์ƒํ™ฉ๋งˆ๋‹ค ์•Œ๋งž์€ ๋ฉ”์†Œ๋“œ๋ฅผ ์ •์˜ํ•˜๊ณ  ํ˜ธ์ถœํ•ด์ค˜์•ผํ•˜๊ฒŒ๋•Œ๋ฌธ์— ์ฝ”๋“œ๊ฐ€ ๊ต‰์žฅํžˆ ๋”๋Ÿฌ์›Œ์งˆ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋œ๋‹ค..

 

 

 

์ฟผ๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋‚˜๊ฐ€๋Š”์ง€ ํ…Œ์ŠคํŠธ ํ•ด๋ด…๋‹ˆ๋‹ค.

@Test
@DisplayName("pageNation ์ฟผ๋ฆฌ ํ™•์ธ")
public void findBySlice(){
    Slice<Post> slice = postRepository.findAllByIdLessThanOrderByIdDesc(3L,PageRequest.of(0,10));
    System.out.println(slice.hasNext());
}

Slice๋กœ ๋ฐ˜ํ™˜๊ฐ’์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ limit์œผ๋กœ 'ํŽ˜์ด์ง€ ์‚ฌ์ด์ฆˆ  + 1'๊ฐ€ ๋‚ ๋ผ๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ ๋ฐ์ดํ„ฐ์˜ ์œ ๋ฌด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•œ ๋™์  ์ฟผ๋ฆฌ

@Override
public Slice<OrderByStoreResponse> findBy(String storeId, OrderStatus orderStatus, 
	String cursorOrderId, Pageable pageable) {

		List<OrderByStoreResponse> result = query.select(order)
			.from(order)
			.leftJoin(order.orderItems, orderItem)
			.leftJoin(orderItem.item, item)
			.leftJoin(orderItem.customOption, customOption)
			.leftJoin(user).on(user.id.eq(order.userId))
			.where(
				generateCursorId(cursorOrderId, pageable.getSort()),
				order.storeId.eq(storeId),
				order.orderStatus.eq(orderStatus)
			)
			.limit(pageable.getPageSize() + 1)
			.orderBy(getOrder(pageable)) // ์ •๋ ฌ ๋ฐฉ์‹์„ ๊ตฌํ•˜๋Š” ๋ฉ”์†Œ๋“œ
			.orderBy(order.id.desc());
	
		return SliceUtil.toSlice(result, pageable);
}

private BooleanExpression generateCursorId(String cursorOrderId, Sort sort) {
		if (cursorOrderId == null) {
			return null;
		}
		return order.id.lt(cursorOrderId);
}

fetch join์„ ํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ฟผ๋ฆฌ์ด๋‹ค. id๊ฐ€ null์ผ ๊ฒฝ์šฐ ํ•ด๋‹น ์กฐ๊ฑด์€ ์ž๋™์œผ๋กœ ์ ์šฉ์ด ์ œ์™ธ๋˜๊ธฐ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ ์ฟผ๋ฆฌ๋ฅผ ์งค ํ•„์š”๊ฐ€ ์—†์–ด์กŒ๋‹ค.

 

 

Cursor ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์˜ ๋ฌธ์ œ์ 

 

cursor ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ๋‹ˆํฌํ•˜์ง€ ์•Š์„ ์ˆ˜ ์•Š๋‹ค. (๋‚ ์งœ ๊ฐ™์€)

→ ๋ฐ์ดํ„ฐ ๋ˆ„๋ฝ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

→ cursor ๋ฐ์ดํ„ฐ + ์œ ๋‹ˆํฌ id๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•˜๋ฉด ํ•ด๊ฒฐ!

์ด๋•Œ or ์—ฐ์‚ฐ์ž์˜ ๊ฒฝ์šฐ ์ธ๋ฑ์Šค๋ฅผ ํƒ€์ง€์•Š์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฃผ์˜ํ•œ๋‹ค.

 

 

 

 

 

reference.

https://wonyong-jang.github.io/database/2020/09/06/DB-Pagination.html

 

 

 

์ž˜๋ชป๋œ ์ •๋ณด๊ฐ€ ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€์„ ํ†ตํ•ด ์•Œ๋ ค์ฃผ์„ธ์š”. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋Œ“๊ธ€