Spring Batch 3 - Items(Reader)

2024. 3. 20. 13:21·Spring/Batch Programming

2024.03.13 - [Spring/Batch Programming] - Spring Batch Step

 

Spring Batch Step

2024.03.13 - [Spring/Batch Programming] - Spring Batch Job Spring Batch Job 2024.03.12 - [Spring/Batch Programming] - Spring Batch 도메인 용어, 실전 Spring Batch 도메인 용어, 실전 2024.03.10 - [Spring/Batch Programming] - Spring Batch 실습(

lsdiary.tistory.com

지난 글까지 Step에 대해서 전반적으로 알아봤다.

 

이번에는 예전에 직접 구현해봤던 Item 3개에 대해서 알아보고자 한다.

 

ItemReader

ItemReader 인터페이스

보다시피 read() 하나의 메소드만 존재한다.

※null을 리턴하면 배치가 정상적으로 종료된다. → 정상적으로 배치가 진행되고 싶으면 reader에서 null을 리턴하면 안된다!

 

 입력형식
  • 파일(Flat, JSON, XML)
Flat : 파일을 여는거 부터 어렵다,,,, 그래서 스프링 배치는 간단하게 빌더패턴으로 할 수있도록  기능을 제공해준다!

FlatFileItemReader  구조도
LineMapper 인터페이스

라인을 읽어서 객체로 반환해준다.

 

구현체

,(콤마) 등 구분되어 있는 토큰을 가져온다. 그 이후 FieldSetMapper를 통해 나뉘어진 토큰들을 클래스로 매핑 시켜준다.

 

필드셋을  만듬

 

필드셋 획득 후 객체로 변환 시켜줌

FlatFileItemReader의 여러가지 속성

Property Type
comments - 주석은 스킵해라(디폴트 설정 : #) String[]
encoding String
lineMapper LineMapper
linesToSkip - 스킵을 최초에 얼마나? int
recordSeparatorPolicy - 각 줄의 마지막을 정의(정의 안하면 개행문자로 넘어감) RecordSeparatorPolicy
resource Resource
skippedLinesCallback - 라인을 스킵할때, 콜백을 호출해서 원하는 작업 수행 LineCallbackHandler
strict - 파일이 없는 경우에 throw를 발생시킨다.(false로 설정할 경우, 배치처리는 정상적으로 진행된다.) boolean
실습

테스트를 위해 만든 파일 users.txt

Configuration 소스코드
@Configuration
public class ItemReaderJobConfiguration {

    @Bean
    public Job job(
            JobRepository jobRepository,
            Step step){
        return new JobBuilder("itemReaderJob", jobRepository)
                .incrementer(new RunIdIncrementer())
                .start(step)
                .build();

    }

    @Bean
    public Step step(
            JobRepository jobRepository,
            PlatformTransactionManager transactionManager,
            ItemReader<User> flatFileItemReader
    ){
        return new StepBuilder("step", jobRepository)
                .<User, User>chunk(2, transactionManager)
                .reader(flatFileItemReader)
                .writer(System.out::println)
                .build();
    }

    @Bean
    public FlatFileItemReader<User> flatFileItemReader(){
        return new FlatFileItemReaderBuilder<User>()
                .name("flatFileItemReader")
                .resource(new ClassPathResource("users.txt"))
                .linesToSkip(2)
                .delimited().delimiter(",")
                .names("name", "age", "region", "telephone")
                .targetType(User.class)
                .build();
    }
}

Chunk size대로 잘 작동하는 것을 확인할 수 있다.

그렇다면 구분자가 없을때는 어떻게 데이터를 구별해서 읽을 수 있을까?

@Bean
    public FlatFileItemReader<User> fixedLengthFlatFileItemReader(){
        return new FlatFileItemReaderBuilder<User>()
                .name("fixedLengthFlatFileItemReader")
                .resource(new ClassPathResource("usersFixedLength.txt"))
                .linesToSkip(2)
                .fixedLength()
                .columns(new Range[]{new Range(1,2), new Range(3,4), new Range(5,6), new Range(7,19)})
                .names("name", "age", "region", "telephone")
                .targetType(User.class)
                .strict(true)
                .build();
    }

 

Range로 직접 가져오는 방법이 있다.

JSON

JSON의 경우 Flat 보다 훨씬 간단하다. 개발을 해본 사람이라면 다들 알고 있을 JSON 파일이다.

[
 {
  "name":"승우",
  "age":26,
  "region":"서울",
  "telephone":010-1234-5678"
 },
 {
  "name":"길동",
  "age":9999,
  "region":"부산",
  "telephone":"010-8765-4321"
 }
]

 

데이터가 많아질수록 보기 편하다는 장점이 있다.

당연히 Spring에서 간단하게 코드 몇줄  작성하면 읽어들일수 있는 기능이 있다.

JsonObjectReader 인터페이스 구조도

내가 원하는 클래스로 사용할  수 있다. 이것을 전략패턴 이라고 한다. 

스프링은 정말 미친 프레임워크다,,,,, 다되어 있다 진짜로,,,

실습

 

	implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'

그냥 코드를 짜고 돌리면 의존성 오류가 난다. 꼭 build.gradle에 json의존성을 추가하고 진행하자!

 

 

 @Bean
    public JsonItemReader<User> jsonItemReader(){
        return new JsonItemReaderBuilder<User>()
                .name("jsonItemReader")
                .resource(new ClassPathResource("users.json"))
                .jsonObjectReader(new JacksonJsonObjectReader<>(User.class))
                .build();
    }

출력이 잘 되는 것을 확인할 수 있다.

 

  • Database

읽는 방법이 Paging과, Cursor 두가지로 나뉜다.

Paging : 여러건 조회

Cursor : 단건 조회(BUT, connetion 유지를 해줘야하므로, 연결시간을 길게 잡아줘야 한다.)

또한 여러가지 구현체들이 있지만, 자주 사용하는 Jpa를 살펴보겠다.

 

JpaPagingItemReaderBuilder의 여러가지 속성

queryProvider(JpaQueryProvider) 쿼리에 대한 제공자
saveState(boolean)  executeContext에 상태를 저장할지 여부
저장하면 다시 돌릴때 그 지점부터 시작
entityManagerFactory(EntityManagerFactory)  
queryString(String)  
currentItemCount(int)  
parameterValues(Map<String, Object>) SQL쓸 때 필요한 파라미터값을 Map으로 제공가능
transacted(boolean)  
maxItemCount(int)  
name(String)  
pageSize(int)  
build()  

 

 

JpaCursorItemReaderBuilder의 속성은 Paging과 다를게 없으므로 넘어가겠다.

 

 

  • HTTP API
  • Message Queue
실습

 

실습에 앞서 datagrip으로 DB에 테이블을 직접 추가 해줬다.

USER 테이블

application.properties

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

또한 이름으로 테이블을 실제 DB 테이블과 매핑 해주기위해서 테이블 이름으로 매핑해주는 설정을 추가해주자.

 

@Data
@Entity
@Table(name = "USER")
@NoArgsConstructor
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private String name;
    private String age;
    private String region;
    private String telephone;
}

JPA에서 Entity 프록시를 만들기 위해 반드시 기본 생성자가 하나를 생성해야 하기 때문에 @NoArgsConstructor 어노테이션을 붙여준다.

 

이제 DB에 대한 연결은 끝났다. 테스트를 해보자

 

paging

@Bean
    public ItemReader<User> jpaPagingItemReader(
            EntityManagerFactory entityManagerFactory
    ){
        return new JpaPagingItemReaderBuilder<User>()
                .name("jpaPagingItemReader")
                .entityManagerFactory(entityManagerFactory)
                .pageSize(3)
                .queryString("SELECT u FROM User u ORDER BY u.id")
                .build();
    }

데이터를 잘 가지고 오는 것을 확인 할수있다.

 

cursor

 @Bean
    public ItemReader<User> jpaCursorItemReader(
            EntityManagerFactory entityManagerFactory
    ){
        return new JpaCursorItemReaderBuilder<User>()
                .name("jpaCursorItemReader")
                .entityManagerFactory(entityManagerFactory)
                .queryString("SELECT u FROM User u ORDER BY u.id")
                .build();
    }

 

더 쉽다,,,

 

이렇게 간단하게 ItemReader에 대해서 알아보았다. 다음은 ItemWriter 차례이다.

 

2024.03.20 - [Spring/Batch Programming] - Spring Batch 3 - Items(Writer)

 

Spring Batch 3 - Items(Writer)

2024.03.20 - [Spring/Batch Programming] - Spring Batch 3 - Items(Reader) Spring Batch 3 - Items(Reader) 2024.03.13 - [Spring/Batch Programming] - Spring Batch Step Spring Batch Step 2024.03.13 - [Spring/Batch Programming] - Spring Batch Job Spring Batch Jo

lsdiary.tistory.com

 

'Spring > Batch Programming' 카테고리의 다른 글

Spring Batch 3 - Items(Processor)  (0) 2024.03.25
Spring Batch 3 - Items(Writer)  (0) 2024.03.20
Spring Batch Step  (0) 2024.03.13
Spring Batch Job  (0) 2024.03.13
Spring Batch 도메인 용어, 실전  (3) 2024.03.12
'Spring/Batch Programming' 카테고리의 다른 글
  • Spring Batch 3 - Items(Processor)
  • Spring Batch 3 - Items(Writer)
  • Spring Batch Step
  • Spring Batch Job
Ls._.Rain
Ls._.Rain
안되면 될때까지 삽질했던 기록
  • Ls._.Rain
    Ls{Diary}
    Ls._.Rain
  • 전체
    오늘
    어제
    • 분류 전체보기 (136)
      • Github (2)
      • Spring (51)
        • Batch Programming (13)
        • 결제 (4)
        • 대용량 트래픽 (32)
        • OpenAI (0)
        • Security (0)
        • WebSocket (0)
        • JPA (1)
      • Algorithm (67)
        • DFS (6)
        • BFS (6)
        • Dynamic Programming (10)
        • Brute Force (4)
        • Binary Search (6)
        • 구현, 시뮬레이션 (15)
        • Stack (1)
        • Greedy (4)
        • Priority_Queue (2)
        • Back Tracking (3)
        • Geometry (2)
        • SCC (1)
        • 투포인터 (4)
        • 최대유량 (1)
        • 정렬 (1)
      • OS (0)
      • DevOps (15)
        • AWS (11)
        • Docker (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • hELLO· Designed By정상우.v4.10.0
Ls._.Rain
Spring Batch 3 - Items(Reader)
상단으로

티스토리툴바