본문 바로가기
코드 스테이츠

페이지네이션(Pagination)

by 한휘용 2023. 6. 20.
728x90

페이지네이션(Pagination)

페이지네이션(Pagination)은 데이터를 페이지 단위로 나누어 보여주는 기능을 제공하는 것을 말합니다.

 

만약100개의 데이터가 있다면 이를 페이지네이션을 통해서 10개씩 나누어 10개의 페이지로 표시할 수 있습니다.

데이터베이스나 다른 소스에서 가져온 데이터를 페이지로 나누어 사용자에게 보여줄 때 주로 사용됩니다.

 

페이지네이션은 데이터베이스 액세스 기술을 통해 구현이 가능합니다.

Spring Data 프로젝트에서는 다음과 같은 데이터베이스 액세스 기술들을 지원합니다.

 

  1. Spring Data JPA: Java Persistence API (JPA)를 위한 Spring Data 기술로, ORM(Object-Relational Mapping) 기술을 사용하여 관계형 데이터베이스와 상호작용합니다.
  2. Spring Data JDBC: 관계형 데이터베이스와 상호작용하기 위한 간단하고 직관적인 Spring Data 기술로, JDBC(Java Database Connectivity)를 사용하여 데이터 액세스를 처리합니다.
  3. Spring Data MongoDB: MongoDB와 상호작용하기 위한 Spring Data 기술로, NoSQL 데이터베이스인 MongoDB에 대한 지원을 제공합니다.
  4. Spring Data Redis: Redis와 상호작용하기 위한 Spring Data 기술로, 인메모리 데이터 스토어인 Redis에 대한 지원을 제공합니다.
  5. Spring Data Elasticsearch: Elasticsearch와 상호작용하기 위한 Spring Data 기술로, 실시간 검색 및 분석을 위한 오픈 소스 분산 검색 엔진인 Elasticsearch에 대한 지원을 제공합니다.
  6. Spring Data R2DBC: R2DBC(Reactive Relational Database Connectivity)는 비차단적인 데이터베이스 액세스 라이브러리로, 비동기 프로그래밍을 위한 리액티브 데이터베이스 액세스를 제공합니다. Spring Data R2DBC는 리액티브 관계형 데이터베이스와의 통합을 지원합니다.
  7. Spring Data Couchbase: Couchbase는 NoSQL 문서 데이터베이스입니다. Spring Data Couchbase는 Couchbase와의 통합을 제공하여 JSON 문서와 작업하고 Couchbase 서버에서 CRUD 작업을 수행할 수 있습니다.
  8. Spring Data Cassandra: Cassandra는 고도로 확장 가능한 NoSQL 데이터베이스입니다. Spring Data Cassandra는 Cassandra와의 통합을 제공하여 데이터베이스에 대한 CRUD 작업과 쿼리를 수행할 수 있습니다.

 

이 중 페이지네이션을 구현할 수 있는 액세스 기술은 아래와 같습니다.

  • Spring Data JPA
  • Spring Data JDBC
  • Spring Data MongoDB

 

이번엔 페이지네이션 구현 방식을 알아보겠습니다.

페이지네이션은 주로 오프셋(offset) 방식커서(cursor) 방식이 사용됩니다.

 

1. 오프셋(offset) 방식

오프셋 방식은 페이지 번호와 페이지당 아이템 수를 기준으로 동작합니다.

 

예를 들어, 사용자가 페이지당 10개의 아이템을 요청했다고 가정하면, 첫 번째 페이지를 가져올 때는 데이터의 처음부터 10개의 아이템을 가져옵니다. 다음으로 두 번째 페이지를 요청하면, 다시 데이터를 처음부터 검색해서 데이터의 11번째부터 20번째 아이템을 가져옵니다. 이런 식으로 페이지 이동이 발생할 때마다 데이터의 일부를 건너뛰고 원하는 페이지의 아이템을 추출합니다.

 

2. 커서(cursor) 방식

커서 방식은 이전 페이지의 마지막 아이템을 기준으로 다음 페이지를 탐색하는 방법으로 동작합니다.

 

예를 들어, 사용자가 페이지당 10개의 아이템을 요청했다고 가정하면, 첫 번째 페이지의 데이터를 가져올 때는 시작 커서를 지정하지 않습니다. 첫 번째 페이지를 보여준 후, 마지막 아이템의 커서 값을 기억하고 있다가 사용자가 두 번째 페이지를 요청하면, 이전 페이지의 마지막 아이템의 커서 값을 사용하여 다음 페이지의 데이터를 가져옵니다.

 

오프셋 방식의 장점

  1. 구현이 비교적 간단하고 직관적입니다.
  2. 작은 규모의 데이터셋에서는 일관된 성능을 유지할 수 있습니다.
  3. 데이터의 순서가 중요하지 않은 경우에 유용합니다.

오프셋 방식의 단점

  1. 대량의 데이터셋에서 페이지 이동이 많을 때 성능 저하가 발생할 수 있습니다. 매번 데이터의 일부를 건너뛰어야 하기 때문에 데이터베이스 부하가 크게 증가할 수 있습니다.
  2. 데이터의 순서가 중요한 경우에는 문제가 발생할 수 있습니다. 새로운 데이터가 추가되거나 삭제되면 오프셋 값이 변경되어 원하는 결과를 얻기 어려울 수 있습니다.

 

커서 방식의 장점

  1. 대량의 데이터셋에서도 일관된 성능을 유지할 수 있습니다. 페이지 이동이 많아도 이전 페이지의 마지막 아이템을 기준으로 다음 페이지를 가져오기 때문에 데이터베이스 부하가 상대적으로 작습니다.
  2. 데이터의 순서가 중요한 경우에 유용합니다. 정렬된 데이터에서 특정 시점 이후의 데이터를 가져올 때 커서 방식은 효율적입니다.

커서 방식의 단점

  1. 구현이 상대적으로 복잡할 수 있습니다. 이전 페이지의 마지막 아이템을 추적하고 다음 페이지를 가져오는 로직이 추가로 필요합니다.
  2. 커서 값을 관리해야 하므로 상태를 유지해야 합니다. 이는 서버 측에서 상태를 관리하거나 클라이언트 측에서 커서 값을 유지하는 등의 추가적인 처리를 필요로 합니다.

 

이제 페이지네이션을 Spring Data JDBC를 통해 오프셋 방식으로 구현해 보겠습니다.

 

PageInfo

먼저 요구사항에 맞춰 PageInfo를 생성해야 합니다.

PageInfo에는 조회하는 page의 정보가 포함되어야 합니다.

  • page = 페이지 번호
  • size = 한 페이지에 포함되는 데이터 row(행)의 개수
  • totalElements = 테이블에 저장되어 있는 데이터의 총 개수
  • totalPages = 총 페이지수

PageInfo 생성

repository

Spring Data JDBC가 제공하는 CrudRepository 를 상속받아 Repository를 구현합니다.

 

매개변수로 Pageable 타입의 객체를 넘겨주면, 객체의 정보를 읽고 page 조건을 설정하여 데이터를 가져옵니다.

 

여기서 findAllByOrderByMemberIdDesc() 는 "memberId를 기준으로 내림차순으로(최신순) 모든 정보를 가져온다."입니다.

 

CrudRepository를 상속받아 Repository를 구현

 

Service

pagesize를 매개변수로 받는 PageRequest 객체를 생성하여 repository로 반환합니다.

PageRequestPageable 인터페이스의 구현 클래스입니다.

Request 객체 생성 후 repository로 반환

 

DTO

전체 멤버의 정보를 담고있는 data 와 pageInfo 를 필드로 받는 Dto 클래스 생성한다.

MemberPageDto 생성

 

Controller

사용하려는 MemberController의 getMembers() 핸들러 메서드에

@RequestParam을 사용해서 page와 size의 파라미터를 전달받아야 합니다.

@Positive로 0보다 큰 숫자만 가능하다는 유효성 검증도 적용합니다.

 

실제 페이지는 1부터 시작하지만 데이터 엑세스 계층에서 페이지를 접근할 때는 0부터 시작하므로 page에서 1을 빼줍니다.

MemberController 구현

 

이후 Postman 을 사용해서 page 와 size 의  파라미터 값을 입력한 후, get 메서드를 실행하면 결과가 나온다

Postman 파라미터 값 입력

파라미터 값에 해당하는 내용 출력

Postman 결과

728x90

'코드 스테이츠' 카테고리의 다른 글

테스팅(Testing) - 단위 테스트  (0) 2023.06.28
트랜잭션(Transaction)  (0) 2023.06.26
DDD(Domain Driven Design),애그리거트(Aggregate)  (0) 2023.06.19
Spring Data JDBC  (0) 2023.06.18
JDBC  (0) 2023.06.16