Spring/Spring Data JPA

[Spring Data JPA] 3-2. JPA Query Methods (5)

noahkim_ 2024. 8. 2. 15:49

8. Scrolling

  • 대규모 결과 집합을 작은 청크 단위로 처리할 수 있음 
  • 모든 결과를 메모리에 로드 X (효율적으로 처리)
기능 설명
Window<T>
스크롤링 중 반환되는 청크
- 정보: 현재 청크 데이터 + 위치 정보
ScrollPosition
스크롤링 작업에서 특정 위치를 나타내기 위한 객체
- Offset-based
특정 오프셋 위치부터 데이터를 가져옴
- Keyset-based
키셋 기반으로 데이터를 가져옴 
- non-nullable 정렬 속성 사용
Scrolling Type  
- Offset-based DB에서 전체 결과를 물리화 ✅
- 특정 오프셋 위치부터 데이터를 잘라서 반환
- Keyset-based
DB에서 전체 결과를 물리화
- 인덱스를 활용하여 데이터를 반환
- 오프셋 기반의 단점을 보완

 

예제) ScrollPosition

더보기

offset-based

public interface UserRepository extends Repository<User, Long> {
    // 오프셋 기반으로 특정 lastName을 가진 첫 10개의 User 반환
    Window<User> findFirst10ByLastnameOrderByFirstname(String lastname, OffsetScrollPosition position);
}

// 스크롤링 로직 예시
OffsetScrollPosition position = OffsetScrollPosition.initial();  // 처음부터 시작
Window<User> users;

do {
    // 첫 번째 페이지 (10개 사용자) 가져오기
    users = userRepository.findFirst10ByLastnameOrderByFirstname("Doe", position);
    
    // 가져온 사용자 처리
    for (User user : users) {
        // 사용자 객체 처리
    }
    
    // 다음 페이지 요청
    position = users.positionAt(users.size() - 1);  // 마지막 사용자 위치를 기준으로
} while (!users.isEmpty() && users.hasNext());  // 더 이상 데이터가 없으면 종료

 

Keyset-based

public interface UserRepository extends Repository<User, Long> {
    // 키셋 기반으로 특정 lastName을 가진 첫 10개의 User 반환
    Window<User> findFirst10ByLastnameOrderByFirstname(String lastname, KeysetScrollPosition position);
}

// 스크롤링 로직 예시
KeysetScrollPosition position = KeysetScrollPosition.initial();  // 처음부터 시작
Window<User> users;

do {
    // 첫 번째 페이지 (10개 사용자) 가져오기
    users = userRepository.findFirst10ByLastnameOrderByFirstname("Doe", position);
    
    // 가져온 사용자 처리
    for (User user : users) {
        // 사용자 객체 처리
    }
    
    // 다음 페이지 요청 (마지막 사용자의 ID를 기준으로)
    position = users.positionAt(users.get(users.size() - 1).getId());  // 마지막 사용자의 ID 기준
} while (!users.isEmpty() && users.hasNext());  // 더 이상 데이터가 없으면 종료

 

예제) Scrolling Type

더보기

Offset-based 

interface UserRepository extends Repository<User, Long> {
  Window<User> findFirst10ByLastnameOrderByFirstname(String lastname, OffsetScrollPosition position);
}

WindowIterator<User> users = WindowIterator.of(position -> repository.findFirst10ByLastnameOrderByFirstname("Doe", position))
  .startingAt(OffsetScrollPosition.initial());

 

Keyset-based 

interface UserRepository extends Repository<User, Long> {
  Window<User> findFirst10ByLastnameOrderByFirstname(String lastname, KeysetScrollPosition position);
}

WindowIterator<User> users = WindowIterator.of(position -> repository.findFirst10ByLastnameOrderByFirstname("Doe", position))
  .startingAt(ScrollPosition.keyset());
  • WindowIterator
    • Window를 처리할 때 사용할 수 있는 반복자
    • position을 기준으로 스크롤링 작업 시작
    • 다음 Window<T>를 가져옴 (결과 소진까지 반복)

 

 


출처