상세 컨텐츠

본문 제목

Spring Batch DB 데이터 이관하기

SpringBatch

by 성찬우 2022. 8. 17. 15:12

본문

A라는 테이블에서 B테이블로 데이터를 옮겨야 할때 우리는 어떻게 해야할까?

또는 A라는 정리된 문서를 B테이블로 데이터를 새로이 쓸때 어떻게 해야할까?

 

생각나는 것은 B테이블에서 A테이블을 파라미터로 받는 생성자를 만들어 B테이블에 저장하는 것이 

가장 먼저 떠오를 것 같다. 그렇게 생성된 데이터를 repository에 save하면 되니까 

 

Spring Batch 에서는 프로그램이 시작될 때 이를 자동적으로 처리할 수 있도록 도와준다. 

 

 

Entity 

package
Chef Entity
ChefCarrer Entity

Chef 엔티티

  • id : pk
  • name : 이름
  • age : 나이
  • mainMenu : 주력 메뉴 
  • debut : 일을 시작한 날

 

ChefCareer 엔티티

  • id : pk
  • name : 이름
  • mainMenu : 주력 메뉴 
  • carrer : 경력

repository 는 일반적인 JPA repository 이다. 

 

 

 

SpringBatch Config 를 설정하자

 

 

다음 그림과 같이 Job 과 Step 을 설정해 주자 

@Configuration
@RequiredArgsConstructor
public class chefConfig {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job chefJob(Step chefStep) {
        return jobBuilderFactory.get("chefJob")
                .incrementer(new RunIdIncrementer())
                .start(chefStep)
                .build();
    }

    @JobScope
    @Bean
    public Step chefStep() {
        return stepBuilderFactory.get("icenoodle")
                .build();
    }
}

 

지금 보면 chefStep()이 비어있다. 

앞으로 

  • reader : 어떤 것을 읽어 들일건지
  • processor : 어떻게 처리 할 것인지
  • writer : 어떤것을 쓸지

이렇게 3가지를 설정해 줄 것이다. 

 

Reader

기본적인 틀이다. Bean등록과 StepScope임을 등록하고

ItemWriter 타입으로 리턴타입을 지정한다. 

그리고 Builder 형태로 이를 설정해 줄것인데 <> 안에 어떤 타입의 데이터를 읽어 들일지 설정한다. 

@Bean
@StepScope
public RepositoryItemReader<Chef> chefReader(){
    return new RepositoryItemReaderBuilder<Chef>()
                
}

빌더 타입으로 어떤 것들을 설정해줄 것인가

  • name
  • repository
  • methodName
  • pageSize
  • arguments
  • sorts

를 설정 해줄 것이다. 

@Bean
@StepScope
public RepositoryItemReader<Chef> chefReader() {
    return new RepositoryItemReaderBuilder<Chef>()
            .name("chefReader")
            .repository(chefRepository)
            .methodName("findAll")
            .pageSize(5)
            .arguments(Arrays.asList())
            .sorts(Collections.singletonMap("id", Sort.Direction.ASC))
            .build();

}

전체적인 맥락을 보면

 

chefReader 를 chefRepository 에서 findAll 을 5개씩 배열로 ASC Sort 해서 가져와라 

라는 의미이다. 

 

repository 를 활용하기 위해서 

@Autowired
private ChefRepository chefRepository;
@Autowired
private ChefCareerRepository chefCareerRepository;

이렇게 주입을 잊어서는 안된다.

 

Processor

기본적인 틀입니다. 

람다식으로 ChefCarreer 생성자를 통해서 e를 파라미터로 전달하는 형태의 프로세서이다.

@Bean
@StepScope
public ItemProcessor<Chef, ChefCareer> chefProcessor(){
    return e -> new ChefCareer(e);
}

 

하지만 저희는 아직 ChefCarrer 의 생성자를만들지 않았으므로 간단하게 생성해줄 것이다. 

 

public ChefCareer(Chef chef) {
    this.id = chef.getId();
    this.name = chef.getName();
    this.mainMenu = chef.getMainMenu();
    this.carrer = Year.now().getValue()-chef.getDebut();
}

이렇게 ChefCarrer 클래스에서 어떤식으로 데이터를 전달할지 생성자를 만들어 주었다. 

 

Writer
@Bean
@StepScope
public ItemWriter<ChefCareer> chefWriter(){
    new ItemWriter<ChefCareer>() 
}

ItemWriter를 리턴값으로 받는 chefWirter이다 . 

new ItemWriter<ChefCarrer> 을 하면 오버라이드를 받아 커스텀이 가능하다.(스샷엔 return 을 뺴먹엇네요 ㅠㅠ)

이렇게 오버라이드를 받으면 우리는 파라미터인 items를 모두 ChefCareer Repository에 저장할 것이다. 

@Bean
@StepScope
public ItemWriter<ChefCareer> chefWriter(){
    return new ItemWriter<ChefCareer>() {
        @Override
        public void write(List<? extends ChefCareer> items) throws Exception {

        }
    }
}

이렇게 forEach로 저장을 하게 된다. 

@Bean
@StepScope
public ItemWriter<ChefCareer> chefWriter(){
    return new ItemWriter<ChefCareer>() {
        @Override
        public void write(List<? extends ChefCareer> items) throws Exception {
            items.forEach(e -> chefCareerRepository.save(e));
        }
    };
}

 

Step에 적용하기 

Reader, Processor , Writer를 모두 만들었으니 이 모두를 Step 파라미터로 전달받아서 사용하면된다. 

 

@JobScope
@Bean
public Step chefStep(ItemReader chefReader,
                     ItemProcessor chefProcessor,
                     ItemWriter chefWriter) {
    return stepBuilderFactory.get("chefStep")
            .<Chef, ChefCareer>chunk(5)
            .reader(chefReader)
            .processor(chefProcessor)
            .writer(chefWriter)
            .build();
}

<읽어들인 데이터, 새로이 쓸 데이터> 갯수(5) 로 해석 할 수 있다. 

 

 

 

db 확인

우선 Chef 에 데이터를 넣어 보도록하자. 

CREATE TABLE `spring_batch`.`chef`(
	`id` INT NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(45) NULL,
	`age` INT NULL,
	`main_menu` VARCHAR(45) NULL,
	`debut` INT NULL,
	PRIMARY KEY (`id`))
;


CREATE TABLE `spring_batch`.`chef_career`(
	`id` INT NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(45) NULL,
	`main_menu` VARCHAR(45) NULL,
	`carrer` INT NULL,
	PRIMARY KEY (`id`))
;


INSERT INTO spring_batch.chef(`name`, `age`,`main_menu`,`debut`) values('A',30 ,'MENU-A', 1980);
INSERT INTO spring_batch.chef(`name`, `age`,`main_menu`,`debut`) values('B',29 ,'MENU-B', 1981);
INSERT INTO spring_batch.chef(`name`, `age`,`main_menu`,`debut`) values('C',28 ,'MENU-C', 1982);
INSERT INTO spring_batch.chef(`name`, `age`,`main_menu`,`debut`) values('D',27 ,'MENU-D', 1983);
INSERT INTO spring_batch.chef(`name`, `age`,`main_menu`,`debut`) values('E',26 ,'MENU-E', 1984);

springBatch 실행 

이렇게 실행하여 주고 ChefCareer 을 확인하면 

데이터가 정상적으로 들어온 것을 확인할 수 있다. 

'SpringBatch' 카테고리의 다른 글

SpringBatch 스케줄러로 Job실행하기  (0) 2022.08.19
SpringBatch ExecutionContext  (0) 2022.08.19
Spring Batch Listener  (0) 2022.08.16
Spring Batch 기본 예제.  (0) 2022.08.13
Spring Batch 란?  (0) 2022.08.12

관련글 더보기

댓글 영역