이슈
👉 1. JpaItemWriter Persist 설정 오류
👉 2. Spring Batch 5.0 업데이트로 인한 JobBuilderFactory, StepBuilderFactory Deprecated
👉 3. 데이터 마이그레이션하는 Entity Id 설정 이슈
문제
1. 기존 ADatabase에서 BDatabase로 데이터 마이그레이션
처음에 batch 프로세스를 작성해 본 적이 없어서 에러를 분석하면서 하나씩 변경해 보면서 처음에 설정한 setUsePersist(true)가 올바른 방식임을 알게 되었다.
제대로 된 사용 방식을 이해하기 위해 정리해 보고자 한다.
일단 나는 Spring Batch의 Writer를 JpaItemWriter를 사용해서 처리했다.
setUsePersist의 설정에 따라 “persist” or “merge” 메서드가 설정이 된다.
- setUsePersist(true) ⇒ persist : 새 엔티티를 데이터베이스에 삽입한다. 엔티티가 이미 데이터베이스에 존재하면 예외가 발생한다.
- setUsePersist(false) ⇒ merge : 엔티티가 데이터베이스에 존재하면 업데이트하고, 존재하지 않으면 삽입한다.
@Bean
public JpaItemWriter<Chat> chatWriter() {
JpaItemWriter<Chat> writer = new JpaItemWriter<>();
writer.setEntityManagerFactory(chatEntityManagerFactory);
writer.setUsePersist(true);
return writer;
}
2. Spring Batch 5.0 버전 업데이트
다른 래퍼런스를 참고하면서 Job과 Step을 작성하고 있는데, Spring Batch 5.0 이상부터는 JobBuilderFactory, StepBuilderFactory가 지원하지 않는다고 해서 공식 문서를 참고해서 JobBuilder, StepBuilder를 사용했다.
@Bean
public Job chatJob(JobRepository jobRepository) {
return new JobBuilder("chatJob", jobRepository)
.incrementer(new RunIdIncrementer())
.start(chatStep(jobRepository))
.next(chatLikeStep(jobRepository))
.build();
}
@Bean
public Step chatStep(JobRepository jobRepository) {
return new StepBuilder("chatStep", jobRepository)
.<Chat, Chat>chunk(100, new JpaTransactionManager(chatEntityManagerFactory))
.reader(chatReader())
.writer(chatWriter())
.build();
}
빌더 형식처럼 하나씩 설정해 주면 된다.
먼저 JobBuilder 사용법에 대해 정리하고자 한다.
- JobBuilder : 배치 작업을 설정합니다.
- JobBuilder(”chatJob”, jobRepository) : Job 이름을 정의하고, 적용할 JobRepository를 작성합니다.
- RunIdIncremeter()를 통해 매번 다른 ID를 생성하여 Job을 구분합니다.
- start에는 처음에 시작할 Step을 설정합니다.
- next에는 그다음 시작할 Step을 설정합니다.
- StepBuilder : Job 보다 낮은 단위인 Step을 설정합니다.
- StepBuilder(”chatStep”, jobRepository) : Step 이름을 정의하고, 적용할 JobRepository를 작성합니다.
- chunk : 한 번에 처리할 데이터의 크기를 설정하고 트랜잭션 매니저를 설정합니다. / 트랜잭션 매니저를 통해 멀티 데이터베이스를 일관되게 관리합니다.
- reader : 저장할 데이터베이스를 Reader를 통해 읽습니다.
- writer : 읽은 데이터를 Writer를 통해 BDatabase에 저장합니다.
- 위 코드에는 processor가 없지만, 데이터 형태를 변환하여 저장하는 경우 processor를 정의해서 writer 위 부분에 넣어주면 됩니다.
위 과정을 통해 Spring Batch는 대량의 데이터를 효율적으로 처리할 수 있습니다.
각 Step은 독립적으로 트랜잭션을 관리하며, 실패 시 재시도 및 오류 처리 등의 기능을 제공합니다.
3. 데이터 마이그레이션 ID 충돌 문제
새로운 데이터베이스에 데이터를 마이그레이션 하는데 ID 값이 중복이라는 에러가 발생했습니다.
처음에는 ‘@GeneratedValue(strategy = GenerationType.IDENTITY)’ 를 사용해서 새로운 데이터베이스에 auto_increment 전략을 설정했습니다. 하지만 마이그레이션 과정에서 기존 데이터의 ID 값이 새로운 데이터베이스의 자동 생성된 ID 값과 충돌할 가능성이 있어 ID 생성 전략을 변경해야 함을 알게 되었습니다.
그래서 저는 기존 데이터의 ID 값을 유지하여 마이그레이션 하고자 새로운 데이터베이스에는 ID 값을 수동으로 설정하도록 설정하고 마이그레이션이 끝나면 자동 생성 전략으로 바꾸기로 하였습니다.
// (제거) @GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private Long id;
해결
(1) 나는 새로운 데이터베이스에 데이터를 옮기는 작업을 처리하려 했으므로, setUsePersist(true)로 하는 게 더 효율적인 방법이었다.
(2) Job을 작성하면서 Job을 실행하기 위해 Step, Reader, Writer, Processor, TransactionManager 등 다양한 인터페이스 사용법을 익혔습니다.
다음에는 원하는 속성만 추출하여 Processor를 적용해 보거나 도중에 에러가 발생했을 때 다음 지점부터 실행하는 과정을 연습해보고자 합니다.
(3) 기존 데이터베이스의 ID 키를 유지하기 위해서 새로운 데이터베이스의 엔티티 ID를 수동으로 설정해야 했습니다. 만약 ID 값을 유지하지 않는다고 하면 기존 대로 ID 자동 생성 전략을 설정하고 Processor를 통해 ID를 제외하고 다른 속성들만 추출하여 저장하면 될 것 같습니다.