반응형

Job과 Step의 세부적인 내용을 살펴 보기 전에 스프링 배치를 활용하여 Hello, World 부터 출력을 하겠습니다. 개념도 중요하겠지만 스프링 배치는 코드로 먼저 보는 것이 조금 더 직관적이겠습니다.

 

1. 프로젝트 세팅

start.spring.io 사이트트에서 프로젝트 기본 골격을 생성하였습니다.

 

2. 데이터베이스 생성을 위한 docker-compose.yml 파일 생성

version: '3'

services:
  mysql:
    container_name: mysql_batch
    image: mysql/mysql-server:5.7
    environment:
      MYSQL_ROOT_HOST: '%'
      MYSQL_USER: "test"
      MYSQL_PASSWORD: "test"
      MYSQL_DATABASE: "test"
    ports:
      - "3306:3306"
    command:
      - "mysqld"
      - "--character-set-server=utf8mb4"
      - "--collation-server=utf8mb4_unicode_ci"

mysql 구동을 위해서 yml 파일을 만들어주세요.

3. 설정 요소를 위한 application.yml파일 생성 및 작성

spring:
  profiles:
    active: local
  batch:
    job:
      names: ${job.name:NONE}

---
spring:
  config:
    activate:
      on-profile: local
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: test
    password: test
  jpa:
    show-sql: true
    generate-ddl: false
    hibernate:
      ddl-auto: none
  batch:
    jdbc:
      initialize-schema: ALWAYS

---
spring:
  config:
    activate:
      on-profile: test
  jpa:
    database: h2

데이터베이스 생성 및 배치 구동시 파라미터 전달을 위한 application.yml파일을 작성하였습니다.

4. 도커 명령어를 통해서 데이터베이스 구동

docker-compose up -d

5. main 함수에 배치 수행을 위한 어노테이션 추가

EnableBatchProcessing 어노테이션을 추가해주세요. 이후에 구동을 하고 데이터베이스 테이블을 보게 되면 배치 관련 테이블이 자동으로 생성된 모습을 보실 수 있습니다.

6. job 패키지 생성 및 HelloJobConfig 파일 생성

@Configuration
@RequiredArgsConstructor
public class HelloJobConfig {

    private final JobBuilderFactory jobBuilderFactory;

    private final StepBuilderFactory stepBuilderFactory;

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

    @JobScope
    @Bean
    public Step helloStep(Tasklet tasklet) {
        return stepBuilderFactory.get("helloStep")
                .tasklet(tasklet)
                .build();
    }

    @StepScope
    @Bean
    public Tasklet tasklet() {
        return (contribution, chunkContext) -> {
            System.out.println("Hello Spring batch");
            return RepeatStatus.FINISHED;
        };
    }
}

helloJob이라는 하나의 잡을 생성하고, step을 하나 만들었습니다. step을 구동하기 위해서는 이번 코드에서는 tasklet을 사용하였는데요.

step을 구성하는 방법은 2가지 있습니다. 하나는 tasklet 방식과 다른 방식은 앞전의 설명을 드린 itemReader / itemProcessor / itemWriter 방식으로 처리하는 방식이 있습니다.

간단한 배치 작업은 tasklet 방식을 사용하고 두번째 방법은 차차 살펴 보도록 하겠습니다.

 

7. 수행 시 아래의 파라미터를 넘겨주세요.

--spring.batch.job.names=helloJob

 

반응형
반응형

스트림 처리를 위한 단계별 흐름을 살펴보겠습니다.

스트림처리는

소스(컬렉션, 배열, 파일) -> 오리지날 스트림 -> 필터링처리(중간처리) -> 매핑 처리(중간처리)  -> 집계처리(최종처리) -> 결과

순서로 처리가 됩니다. 이런 순서로처리가 되고 난 이후에 대량의 데이터를 가공해서 축소 하는것을 리덕션이라고 불리겠습니다.

 

샘플)

List<Member> list = Arrays.asList(
    new Member("홍길동", Member.MALE, 30),
    new Member("김나리", Member.FEMALE, 20),
    new Member("신용권", Member.MALE, 45),
    new Member("박수미", Member.FEMALE, 27)
);

double ageAvg = list.stream()
    .filter(m->m.getSex()==Member.MALE)	// 남자요소
    .mapToInt(Member::getAge)			// 나이요소
    .average()							// 집계처리
    .getAsDouble();						// double 출력을 위한 함수 호출

System.out.println("남자 평균 나이: " + ageAvg);

샘플 내용은 남자의 평균 나이를 구하는 구문입니다.

 

Member 변수라는 소스(회원 컬렉션, 리스트)가 있고 -> 오리지날 스트림(Member-남/녀) -> 남자요소 (Member-남)(필터링-중간처리) -> 나이 요소(age)(매핑-중간처리) -> 집계처리(average())(최종처리) -> 남자의 평균나이(결과)

 

각각의 파이프라인 별로 데이터 처리가 되겠습니다.

 

코드 내용)

이것이 자바다 (신용권의 Java 프로그래밍 정복)

반응형
반응형

자바 스트림이란 리스트나, 배열 같은 저장 요소를 for(이터레이터)를 사용하지 않고, 람다식이라는 함수적 스타일을 활용해서 데이터 처리를 할 수 있습니다. 이런 이야기만 듣고 보기에는 이해하기 어려우니 코드를 먼저 살펴 보겠습니다.

기본 샘플)

 

List<String> list = Arrays.asList("홍길동", "신용권", "감자바");

// Iterator 이용
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String name = iterator.next();
    System.out.println(name);
}

System.out.println();

// Stream 이용
Stream<String> stream = list.stream();
stream.forEach(name -> System.out.println(name));

Iterator를 사용하면 반복문을 사용하여 하나씩 접근 하였습니다.

하지만, stream을 활용하면 반복문 없이 리스트 데이터를 처리할 수 있습니다. 위의 내용은 단순히 리스트 출력을 하였는데 아래 코드는 조금더 복작합 작업을 진행합니다.

 

샘플2)

List<Student> list = Arrays.asList(
    new Student("홍길동", 90),
    new Student("신용권", 92)
);

Stream<Student> stream = list.stream();
stream.forEach(s -> {
    String name = s.getName();
    int score = s.getScore();
    System.out.println(name + "-" + score);
});

list문의 stream을 열어서 s라는 변수의 각각의 객체를 받아서 처리를 진행합니다.

 

스트림의 장점은 병렬 처리를 통해서 더 빠른 처리를 할 수 있습니다. 병렬 처리는 하나의 코어로 처리하는 것이 아닌 다수의 코어로 작업을 나눠서 진행하기 때문에 단순 반복문 처리보다 더 빠른 속도를 낼 수 있습니다.

 

샘플3)

List<String> list = Arrays.asList("홍길동", "신용권", "감자바", "람다식", "박병렬");

// 순차 처리
Stream<String> stream = list.stream();
stream.forEach(ParallelExample :: print);

System.out.println();

// 병렬 처리
Stream<String> parallStream = list.parallelStream();
parallStream.forEach(ParallelExample :: print);

병렬 처리를 하면 더 빠른 속도를 낼 수 있지만, 병렬 처리 후 마지막에 합쳐지기 때문에 순서는 보장 받을 수 없습니다.

이점은 주의를 해주셔야 겠습니다.

순서 보장을 못받음

 

 

코드 내용)

이것이 자바다 (신용권의 Java 프로그래밍 정복)

반응형
반응형

이번 시간에는 스프링 배치의 기본 구조를 살펴 보면서 큰 그림을 그려 보도록 하겠습니다.

기본 개념

JobRepository

JobRepository는 배치 수행을 위한 데이터 (시작 시간, 종료 시간, 상태, 읽기/쓰기, 회수 등) 및 Job의 상태관리를 담당합니다. JobRepository는 스프링 배치 내의 잡런쳐, 잡, 스탭과 같이 컴포넌트들이 데이터를 공유를 하게 됩니다.

JobLauncher

잡런처는 잡을 실행해주는 역할을 합니다. 잡이 실행이 되면 JobRepository에는 작업의 따른 데이터들이 갱신이 되겠습니다.

Job과 Step

Job은 하나의 배치 작업입니다. 배치 작업을 하나 수행한다고 하면 Job을 수행 하는 개념입니다. 그리고 하나의 Job 안에는 한개의 Step 또는 여러개의 Step이 있을 수 있습니다. Step은 하나의 배치 작업 안에, 여러 단계가 있다면 이걸 나눠 놓은 개념입니다. Step은 ItemReader, ItemProcessor, ItemWriter가 있어서 무언가를 읽고 처리하고 쓰기를 진행하겠습니다.

배치 작업이란게 데이터베이스나 api 또는 파일을 읽는 어떤 읽는 작업을 진행하고, 필요한 내용을 처리하겠습니다. 이후에는 다시 파일이나 데이터베이스 같은 곳에 write 하는 작업을 진행하는데요. 배치 작업은 이런 방법으로 정형화가 되어 있어서 스프링 배치에서도 이런 레이어의 모습을 보이고 있습니다.

 

스프링 배치를 활용하여 개발을 한다면 우리는 Job 과 Step, Step의 있는 ItemReader, ItemProcessor, ItemWriter 항목들을 활용하여 개발을 진행하겠습니다.

 

참고 스프링 배치 공식 사이트)

https://docs.spring.io/spring-batch/docs/current/reference/html/domain.html#domainLanguageOfBatch

반응형
반응형

리액트 개발 중에 아래와 같은 경고가 발생 하였습니다.

Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.

 

이유는 컴포넌트 개발 중에 function 컴포넌트에 {}를 사용했기 때문에 발생하였습니다.

{}를 제거하시면 해결이 되는데요.

함수형 컴포넌트에서는 {}사용했을 때 경고를 하여 클래스형으로 변경을 해서 사용을 해주실 수도 있습니다.

반응형

+ Recent posts