작성
·
825
·
수정됨
0
안녕하세요~ 강사님 강의를 보고 스프링 배치 입문해서 열심히 이론부터 실습까지 잘 배우고 있습니다.
몇 가지 궁금한 점이 있어서 이렇게 질문을 드리게 되었습니다.
1.
ItemReader 중에 Repositoryitemreader라는 구현체가 있어서 이게 Spring Data JPA를 지원해 줘서 사용해 보았는데요. 이해가 가지 않는 부분이 있어서 질문드리고자 합니다.
@Bean(name = STEP_NAME)
@JobScope
public Step step1(@Value("#{jobParameters[chunkSize]}") Long chunkSize) {
return stepBuilderFactory.get(STEP_NAME)
.<HistoryEntity, HistoryEntity>chunk(chunkSize.intValue())
.reader(itemReader(null))
.processor(itemProcessor())
.writer(itemWriter())
.build();
}
@Bean(name = JOB_NAME + "_reader")
@StepScope
public RepositoryItemReader<HistoryEntity> itemReader(@Value("#{jobParameters[chunkSize]}") Long chunkSize) {
LocalDateTime now = LocalDateTime.now();
return new RepositoryItemReaderBuilder<HistoryEntity>()
.name(JOB_NAME + "_reader")
.repository(HistoryPagingCrudRepository)
.methodName("findByLeaveDtLessThanEqual")
.pageSize(chunkSize.intValue())
.arguments(List.of(now))
.sorts(Collections.singletonMap("leaveDt", Sort.Direction.DESC))
.build();
}
위와 같은 step과 특정 날짜의 데이터를 조회하는 ItemReader를 구현한 후 아래 ItemWriter 에서
@Bean(name = JOB_NAME + "_writer")
@StepScope
public ItemWriter<HistoryEntity> itemWriter() {
return item -> {
item.forEach(historyEntity -> {
// Id 값을 null로 만드는 메소드
historyEntity.updateRemoveId();
}
);
};
}
Entity의 값을 변경하게 되면 당연히 하나의 chunk 단위에서는 하나의 트랜잭션 이기 때문에 JPA의 dirty check로 인한 Id 값을 지우는 update 쿼리가 나갈거라고 생각했는데 그렇지 않더라고요.
다만,
@Bean(name = JOB_NAME + "_writer")
@StepScope
public ItemWriter<HistoryEntity> itemWriter() {
return item -> {
item.forEach(historyEntity -> {
// Id 값을 null로 만드는 메소드
historyEntity.updateRemoveId();
historyPagingCrudRepository.save(historyEntity)
}
);
};
}
위 코드 historyPagingCrudRepository.save(historyEntity)
를 추가하면 merge가 진행되면서 update 쿼리가 실행되긴 하지만 select 쿼리가 한 번 더 실행돼서 비효율적인거 같다는 생각이 들었습니다.
질문을 정리하자면 ItemReader에서 조회한 Entity가 ItemWriter에서도 영속 상태이기 때문에 Dirty Checking 대상이라고 생각했는데 그렇지 않은 이유가 무엇인가요??
혹시 ItemReader 로 데이터 조회 후 ChunkProvider를 통해 Chunk<I> 를 itemProcessor 또는 ItemWriter로 전달하는 과정에서 준영속 상태가 되는것일까요??
2.
jpaPagingItemReader 으로 데이터 조회 후, ItemWriter 에서 jpaPagingItemReader 의 where 절에 해당하는 컬럼의 값을 수정했을 때 offset(page)로 인해 일부 데이터가 읽히지 않는 문제가 있는것으로 알고있습니다. 이 경우 getPage() 메소드를 override 해서 항상 offset을 0으로 고정시키는 방법으로 해결이 가능한데 Repositoryitemreader 구현체 사용 시 어떤식으로 해결이 가능할까요??
답변 1
0
네
일단 제가 Repositoryitemreader 를 사용해 보지 못해서 정확한 원인은 테스트 해 봐야 될 것 같습니다
일반적으로 JPA 로 배치 처리를 할 경우 JPA 용 트랜잭션이 기본적으로 작동하기 때문에 영속상태가 유지되는 것은 맞습니다
영속 상태 유지는 트랜잭션 안에서 가능한고 더티체킹 반영은 쓰기 지연 SQL 항목들이 트랜잭션이 커밋되는 시점에 이루어지기 때문에 이 두가지가 제대로 처리되고 있는지를 확인해 봐야 합니다
또한 ItemReader 와 ItemWriter 에서 사용하는 EntityManager 가 동일한 트랜잭션을 계속 타고 있는지도 봐야 합니다
제가 보기에는 ItemWriter 로 넘어온 엔터티가 계속 영속상태인지 명확하지 않는 것 같습니다
즉 Repositoryitemreader 의 영속상태가 초기화가 된 것 같습니다
2번 질문은 Repositoryitemreader 를 사용해 봐야 알 것 같습니다
깃 소스 공유 가능하시면 제가 테스트 해 보도록 하겠습니다