Post

RepositoryPagingItemReader 구현과 case 정리

RepositorySeekMethodItemReader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
open class RepositorySeekMethodItemReader<T, E>(  
    chunkSize: Int,  
    initialOffset: E,  
    private val offsetGetter: (T) -> E,  
    private val readBlock: (Int, Int, E) -> List<T>,  
) : AbstractPagingItemReader<T>() {  
    private var offset = initialOffset  
  
    init {  
        super.setPageSize(chunkSize)  
    }  
    override fun doReadPage() {  
        results = readBlock(offset, pageSize)  
        offset = results.last().let(offsetGetter)  
    }  
    override fun doJumpToPage(itemIndex: Int) {}  
}
1
2
3
4
5
6
7
8
// usage
fun reader() = RepositorySeekMethodItemReader(  
    chunkSize = CHUNK_SIZE,  
    initialOffset = 0,  
    offsetGetter = SmsMessage::sequence,  
) { offset, pageSize ->  
    smsMessageRepository.findAllByBlaBla(offset, pageSize).toList()  
}

offset 대상 컬럼이 unique 하지 않은 경우

  • 불러온 item을 모두 delete, update하는 경우, 대상 컬럼이 unique 하지 않아도 문제가 발생하지 않는다.
  • 하지만 모두 delete, update 할거라면, 굳이 Seek Method 쓸 필요 없이 하단의 RepositoryPagingItemReader에 Page 0으로 고정하고 쓰는게 더 나아보인다.
  • 기본적으로 Seek Method는 대상 컬럼이 unique 하다는 전제로 사용해야 한다.

offset 대상 컬럼이 unique 한 경우

복합키(Composite Key)에 대한 Seek Method

복합키에 대한 Seek Method는 불가능하다. (생각해보면 알 수 있다)
Paging이 틀어지면서 중복, 누락 발생 케이스를 생각해보면,

불러온 item을 delete, update 하지 않는 경우

  • Seek Method 말고, 일반적인 Paging 사용하면 된다.

불러온 item을 일부만 delete, update 하는 경우

  • 중복, 누락 없으려면 반드시 CursorItemReader를 써야 한다.
    • 여기서 Cursor는 DB가 관리해주는 Cursor를 의미함
  • DB에 세션 잡고 Cursor 열어둔 채로 ResultSet.next() 해서 하나씩 읽어오는 방식으로 진행

불러온 item을 모두 delete, update 하는 경우

  • Seek Method 사용하지 않고, 항상 Page를 0으로 고정한 일반적인 Paging을 사용하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
open class RepositoryPagingItemReader<T>(  
    chunkSize: Int,  
    private val readBlock: (Int, Int) -> List<T>,  
) : AbstractPagingItemReader<T>() {  
    init {  
        super.setPageSize(chunkSize)  
    }  
    override fun doReadPage() {  
        results = readBlock(page, pageSize)  
    }  
    override fun doJumpToPage(itemIndex: Int) {}  
}
1
2
3
4
5
6
// usage
fun reader() = RepositoryPagingItemReader(  
    chunkSize = CHUNK_SIZE
) { _, pageSize ->  
    smsMessageRepository.findAllByBlaBla(PageRequest.of(0, pageSize)).toList()  
}
This post is licensed under CC BY 4.0 by the author.