

process와 writer를 끝낸 데이터는 ChunkOrientedTasklet을 따라 반환되며,
TaskletStep의 doExecute 메소드에 오게 됩니다.

반환된 후 chunkContext.isComplete를 확인하고,
true가 아니면 attributeQueue에 다시 넣어줍니다.
이 attributeQueue는 무엇인지 살펴보면, ItemReader는 RepeatTemplate의
executeInternal 메소드를 호출합니다.

여기서 getNextResult를 사용하며, attributeQueue에서 가져온 데이터를 확인하여 다음 처리할 항목이 있는지 검사합니다.

이 모든 과정을 거치고 나면 다시 TaskletStep의 로직을 실행합니다.

이 로직은 Reader를 읽어오는 과정입니다.
여기서 ChunkOrientedTasklet으로 Reader를 반복합니다.

아래로 내려가다 보면 이 코드가 보입니다.
getNextResult에서 결과를 받아온 후,
isComplete에서 ItemReader에서 받아온 값을 기반으로 반복 여부를 결정하고 있습니다.
제가 사용하는 MyBatisPagingItemReader에서
어떻게 isComplete를 설정하는지 확인해봐야 합니다.
MyBatisPagingItemReader는 이름에서 보듯이 페이징 단위로 처리가 이루어집니다.
다음과 같은 파라미터를 통해 페이징을 구현할 수 있습니다.
[사용법]
<select id="exampleselect">
SELECT id, name, job FROM MEMBER ORDER BY id ASC
OFFSET #{_skiprows} LIMIT #{_pagesize}
</select>

MyBatisPagingItemReader.java에서 이 클래스를 살펴보면, 파라미터를 설정해주고 ArrayList인 result에 받아온 queryId와 parameters로 selectList를 실행합니다.

여기서 무한 반복 이슈의 원인을 발견했습니다.
설정한 쿼리에는 페이징 처리가 따로 없었습니다.
구글링에서 자동으로 계산해준다는 것은 파라미터 설정 없이 자동이란 뜻이 아니었습니다.
(파라미터 설정이 필수입니다!)
만약 select * from example과 같은 쿼리라면 무한 반복할 수밖에 없습니다.
페이징 설정을 적절하게 해주니 무한 반복 이슈를 해결할 수 있었습니다.
처음 구현할 때 페이징을 사용하지 않고 예제를 그대로 따라 붙이다가 페이징을 발견하고
겉핥기식으로 본 후 무작정 사용해본 것이 문제였습니다.
역시, 무엇이든 허투루 넘어가서는 안 된다는 교훈을 얻었습니다.