Inflearn brand logo image

인프런 커뮤니티 질문&답변

ehddbs452100님의 프로필 이미지
ehddbs452100

작성한 질문수

죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.

3장. 작전1: 관계형 데이터베이스 읽고 쓰기 (테이블의 심장에 처형장을 세우다 ☠️)

문제상황에 대해서 이해가 안간다.

작성

·

74

·

수정됨

1

이전 청크의 ItemProcessor에서 엔티티를 수정한게 왜 문제인지 이해가 안간다. ItemProcessor에서 데이터를 수정하고 ItemWriter에서 DB에 flush를 할것 같은데 왜 다음 chunk에서 ItemReader에서 doReadPage()로 데이터를 읽는 시점에 의도치 않게 DB에 변경사항이 발생하는가?? 이미 앞선 데이터는 DB에 모두 반영되지 않았는가?? 이전 청크라는 상황이 이해 안된다.

 


이것이 왜 위험한가? 만약 이전 청크의 ItemProcessor에서 엔티티를 수정했다면?

 

doReadPage()에서 데이터를 읽으려는 시점에 의도치 않게 DB에 변경사항이 반영될 수 있다.

 

이는 ItemReader의 책임 범위를 완전히 벗어난 동작이다. ItemReader는 데이터를 읽기만 해야 하는데, 실제로는 데이터 변경까지 일으킬 수 있는 것이다. 더 큰 문제는 이런 동작을 코드를 자세히 들여다보지 않으면 전혀 예상할 수 없다는 점이다.

 

답변 3

2

KILL-9님의 프로필 이미지
KILL-9
지식공유자

> ehddbs452100@/bin/comprehensive_answer:~$ cat jpa_entity_manager_truth.txt
"이전 청크의 ItemProcessor에서 엔티티를 수정한게 왜 문제인지 이해가 안간다. ItemProcessor에서 데이터를 수정하고 ItemWriter에서 DB에 flush를 할것 같은데..."
> KILL-9@/bin/misconception_correction:~$ echo "핵심 오해 수정 필요"

JpaPagingItemReader는 독자적인 EntityManager를 사용한다. 따라서 너가 말한 상황에서도 ItemReader에서 읽은 데이터는 아직 DB에 반영된 게 아니다.

// JpaPagingItemReader의 doOpen()에서
```java
entityManager = entityManagerFactory.createEntityManager(jpaPropertyMap);
```

> KILL-9@/bin/scope_clarification:~$ cat different_entity_managers.txt
그리고 이건 ItemWriter에서 데이터를 쓰고 말고의 문제가 아니다. ItemReader와 ItemWriter는 각각 별도의 EntityManager를 사용하기 때문이다.

 

그리고 이건 ItemWriter에서 데이터를 쓰고 말고의 문제가 아니다. ItemReader와 ItemWriter는 각각 별도의 EntityManager를 사용하기 때문이다.

> KILL-9@/bin/scenario_explanation:~$ echo "설명 편의를 위한 가정 설정"
설명 편의를 위해 청크 사이즈와 페이지 사이즈가 동일하다고 가정하자. 그러면 청크 반복마다 doReadPage()가 한 번씩 호출될 거니까 이해가 빠를 것이다.
> KILL-9@/bin/deadly_flow_reconstruction:~$ cat entity_manager_isolation.txt

// 청크 #1 (Page #1 읽기) - ItemReader의 독립적 EntityManager
doReadPage() {
    tx.begin();
    flush(); // 아직 DB 변경사항 없음 - 문제 없다.
    clear(); 
    // Page 1 데이터 조회 → ItemReader EntityManager의 1차 캐시에 저장
    tx.commit();
}

// 청크 #1 처리 과정
ItemProcessor에서: page1Entity.setStatus("KILL-9"); 
// 💀 ItemReader EntityManager의 1차 캐시에 변경사항 저장됨


// 청크 2 (Page 2 읽기) - 여기서 지옥이 시작된다
doReadPage() {
    tx.begin();
    flush(); // 💀💀💀 ItemReader EntityManager의 1차 캐시 변경사항이 DB에 써짐!
    clear(); // 1차 캐시 정리 (이미 늦었다...)
    // Page 2 데이터 조회 
    tx.commit();
}

 

1

KILL-9님의 프로필 이미지
KILL-9
지식공유자

[CRITICAL SYNCHRONIZATION ALERT] 🔄💀

Detected: Perfect Reader-Developer Mind Sync
Status: IMPRESSIVE
Synchronization Level: 99.9%


> KILL-9@/bin/timing_analysis:~$ echo "오 나와 싱크로나이즈드되었구나" 💀

안그래도 오늘 JpaPagingItemReader 작성자의 작성 의도에 대한 고찰을 다시 한 번 깊게 했었는데 말이다.

> KILL-9@/bin/preparation_mode:~$ cat deployment_schedule.txt

Current Status: Preparation Phase
ETA: 약 1시간 후
Tasks:
- 집 도착 ✓ (전장 진입)
- 옷 갈아입기 ✓ (전투복 착용)
- 노트북 챙기기 ✓ (무기 점검)
- 심층 분석 준비 ✓ (뇌 가동)

0

안녕하세요, 인프런 AI 인턴입니다.

ehddbs452100님, 질문하신 문제는 Spring Batch에서 청크(Chunk) 기반 프로세싱이 어떻게 작동하는지에 대한 이해와 관련이 있습니다. Spring Batch의 청크 프로세싱은 ItemReader, ItemProcessor, ItemWriter 간의 데이터 흐름으로 구성됩니다.

문제 상황을 자세히 이해하기

  1. 청크 기반 처리 구조:

    • ItemReader가 데이터를 읽어옵니다.
    • ItemProcessor가 데이터를 처리(변경)합니다.
    • ItemWriter가 처리된 데이터를 영속성 계층(예: DB)에 반영합니다.
  2. 데이터 읽기와 변경의 타이밍:

    • 청크 단위로 작동하다 보니, 처음 청크에서 읽고, 처리하며, 기록(쓰기)하기 전까지, 그 데이터는 메모리상에 유지됩니다.
    • 그러나 청크의 마지막 단계에서 DB에 반영됩니다. 이는 동일 트랜잭션 내에서 여러 데이터 조작이 이루어졌지만, 최종적으로 커밋하기 전까지는 변경사항이 DB에 반영되지 않는다는 것을 의미합니다.
  3. 문제 상황 이해하기:

    • ItemProcessor에서 엔티티를 변경하고, ItemWriter가 이 변경된 데이터를 DB에 쓰기 전에, ItemReader가 데이터를 다시 읽게 되어 변경되지 않은 상태의 데이터를 가져오게 될 때, 문제가 발생할 수 있습니다.
    • 특히, ItemReader가 데이터를 flush 하기 전 상태로 다시 읽으려 할 때(ex: doReadPage()), 예상치 못한 데이터 상태 일관성 문제가 발생할 수 있습니다.
  4. 위험성:

    • 이런 방식의 데이터 변경은 ItemProcessorItemWriter 사이의 자연스러운 흐름을 방해할 수 있으며, 특히 예상하지 못한 타이밍에 데이터 반영이 이루어지면, 데이터 일관성 문제가 발생할 수 있습니다.
    • 이는 부정확한 데이터 읽기와 같이 의도치 않은 부작용으로 이어질 수 있기 때문에, 주의가 필요합니다.

이 상황과 관련된 추가적인 정보를 원하시면, 유사한 질문을 다룬 게시물을 참조하세요:
- Batch 처리 중 데이터 일관성 문제에 대한 토론

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

ehddbs452100님의 프로필 이미지
ehddbs452100

작성한 질문수

질문하기