SpringBatch 및 MyBatis를 사용하여 정기적으로 데이터베이스 업데이트

Java에서 인기있는 SpringFramework의 기능 중 하나인 SpringBatch 코드를 업무적으로 사용했기 때문에 소개와 복습과 동시에 집에도 설치해야 합니다.최종 코드는 GitHub 위에 있습니다.

환경

  • Java10
  • CentOS7
  • MySQL5.7
  • 제작


    업무에 쓸 코드를 싣지 못해서 대체할 수 있는 걸 만들고 싶었어요.어떤 사람의 나이 데이터를 생년월일에 따라 정확한 나이로 수정한 것이다.

    데이터


    우선 데이터를 준비하세요.Vagrant에서 CentOS7을 시작하여 MySQL을 설치합니다.batch라는 DB를 만들어서 아래 표를 준비하세요.이번에는 나이와 생년월일이 있으면 좋겠지만 그것만으로도 외로워 이름도 준비했다.겸사겸사 말씀드리지만, 일괄 처리가 매일 운행된다고 가정해 보세요.
    mysql> use batch;
    Database changed
    mysql> desc person;
    +----------+-------------+------+-----+---------+----------------+
    | Field    | Type        | Null | Key | Default | Extra          |
    +----------+-------------+------+-----+---------+----------------+
    | id       | int(11)     | NO   | PRI | NULL    | auto_increment |
    | name     | varchar(30) | NO   |     | NULL    |                |
    | age      | int(3)      | NO   |     | NULL    |                |
    | birthday | date        | NO   |     | NULL    |                |
    +----------+-------------+------+-----+---------+----------------+
    
    4인분 정도의 데이터를 넣습니다.오늘은 8월 29일이기 때문에 달력이 다른 생일 데이터만 넣는다.여분의 업데이트가 있는지 알기 위해 하나는 다른 생일에 준비한다.
    mysql> select * from person;
    +----+-------+-----+------------+
    | id | name  | age | birthday   |
    +----+-------+-----+------------+
    |  1 | Alice |  23 | 1995-08-29 |
    |  2 | Bob   |  38 | 1980-08-29 |
    |  3 | Carol |  29 | 1989-08-29 |
    |  4 | Dave  |  23 | 1995-08-30 |
    +----+-------+-----+------------+
    

    Java 구성 요소


    SpringFramework를 사용할 때 Spring Initializr 에서 모형을 다운로드하는 것이 빠르기 때문에 여기를 사용합니다.Gradle을 사용하기 때문에 Gradle Project를 선택하고 적절하게 입력하십시오.

    종속성의 경우
  • Spring Batch
  • Lombok
  • MyBatis Framework
  • MySQL Driver
  • 각 항목을 적절하게 선택하여 생성된 항목에서 다운로드하고 압축을 풀십시오.여기에 필요한 파일을 추가합니다.Spring Batch의 구조여기에 대해 상세하게 썼기 때문에 읽어보고 싶습니다.
    SpringBatch는 일괄 처리의 실행 단위를 JOB로 정의하고 처리 단위를 STEP로 정의합니다.또한 STEP의 처리 프로세스의 모형으로서 임무표 모델과 정보 블록 모델이라는 두 가지 개념을 준비했다.원래 단일한 표를 갱신하는 것만 참조하면 임무표는 충분하지만, 이번에는 특별히 블록 모형을 이용하여 실시한다.
    블록 모델은'읽기 → 가공 → 쓰기'세 가지 절차로 나누어 실시해야 하며 각각 인터페이스를 준비해야 한다.
    인터페이스
    구현 내용
    ItemReader
    데이터베이스에서 실행 날짜의 월일과 같은 월일의 생년월일을 가진 개인 데이터를 추출한다.
    ItemProcessor
    생년월일에 따라 나이를 계산해 업데이트한 개인 데이터를 만들었다.
    ItemWriter
    생성된 개인 데이터를 데이터베이스에 기록합니다.

    데이터 읽기 및 쓰기


    데이터를 읽고 쓸 때 DB에 연결합니다.마이바티스의 라이브러리는 각자의 인터페이스 구현 클래스를 제공하기 때문에 그곳을 사용하기로 했다.가져오기는 일괄 처리 실행 날짜와 같은 달 날짜를 생일로 하는 개인 기록을 추출합니다.그래서 저는 아래의 SQL을 발매하고 싶습니다.당일 (today) 날짜가 응용 프로그램에서 전달됩니다.
    SELECT
        id,
        name,
        age,
        birthday
    FROM
        person
    WHERE
        Date_format(birthday, '%m%d') = Date_format(#{today}, '%m%d')
    
    쓰기(ItemWriter)는 나이만 업데이트됩니다.
    update
        person
    set
        age = #{age}
    where
        id = #{id}
    

    가공 데이터


    데이터 처리는 추출된 개인 데이터 객체의 나이를 정확하게 조정해야 합니다.그렇긴 하지만 올해와 생일의 차이를 따져 업데이트용 대상을 만들 뿐이다.
    CorrectAgeProcessor.java
    // import省略
    @Component
    @Slf4j
    public class CorrectAgeProcessor implements ItemProcessor<Person, Person> {
        @Override
        public Person process(Person person) throws Exception {
            log.info("Correct {}.", person.getName());
            return new Person(
                    person.getId(),
                    person.getName(),
                    LocalDate.now().getYear() - person.getBirthday().getYear(),
                    person.getBirthday());
        }
    }
    

    작업 구성 정의


    작업 구성을 정의합니다.이번에는 한 단계만 준비하면 충분해 step 빈.SpringBatch는 기본적으로 트랜잭션을 실행하여 chunk(n) 에 설정된 건수 간격에 따라 제출한다고 합니다.어느 정도 집중 제출을 통해 제출 시 비용을 줄이기 위한 것이다.이번에는 매사에 제출해야 한다.
    BatchConfiguration.java
    // import省略
    @Configuration
    @EnableBatchProcessing
    @RequiredArgsConstructor
    public class BatchConfiguration {
    
        public final JobBuilderFactory jobBuilderFactory;
    
        public final StepBuilderFactory stepBuilderFactory;
    
        private final SqlSessionFactory sqlSessionFactory;
    
        private final CorrectAgeProcessor correctAgeProcessor;
    
        @Bean
        public MyBatisCursorItemReader<Person> reader() {
            Map<String, Object> params = new HashMap<>();
            params.put("today", LocalDate.now());
            return new MyBatisCursorItemReaderBuilder<Person>()
                    .sqlSessionFactory(sqlSessionFactory)
                    .queryId("com.github.hysrabbit.agecorrector.mybatis.mapper.PersonMapper.findByBirthday")
                    .parameterValues(params)
                    .build();
        }
    
        @Bean
        public MyBatisBatchItemWriter<Person> writer() {
            return new MyBatisBatchItemWriterBuilder<Person>()
                    .sqlSessionFactory(sqlSessionFactory)
                    .statementId("com.github.hysrabbit.agecorrector.mybatis.mapper.PersonMapper.save")
                    .build();
        }
    
        @Bean
        public Job correctAge(JobListener jobListener, Step step) {
            return jobBuilderFactory.get("correctAge")
                    .incrementer(new RunIdIncrementer())
                    .listener(jobListener)
                    .flow(step)
                    .end()
                    .build();
        }
    
        @Bean
        public Step step(ItemReader<Person> reader, ItemWriter<Person> writer) {
            return stepBuilderFactory.get("step")
                    .<Person, Person> chunk(1)
                    .reader(reader)
                    .processor(correctAgeProcessor)
                    .writer(writer)
                    .build();
        }
    
    }
    
    기타 각양각색의 실현여기은 최종 코드를 전송하고 있다.테스트 코드 등이 설치되지 않았기 때문에 며칠 후에 다시 설치할 생각입니다.
    ySQL이 설치된 가상 시스템에서 실행됩니다.실행하기 전에 환경 변수에 데이터베이스 설정 정보를 정의합니다.
    $ export SPRING_DATASOURCE_URL=jdbc:mysql://<hostname>:<port>/<database>;
    $ export SPRING_DATASOURCE_USERNAME=<username>;
    $ export SPRING_DATASOURCE_PASSWORD=<password>;
    
    그런 다음 Gradle에서 생성된 Jar 파일을 구축하고 실행합니다.삽입된 logger에서 업데이트된 사람의 이름을 출력합니다.
    $ ./gradlew clean build
    .
    .
    .
    $ java -jar build/libs/agecorrector.jar
    
      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.1.7.RELEASE)
    .
    .
    .
    2019-08-29 01:50:29.334  INFO 2781 --- [           main] c.g.h.agecorrector.batch.JobListener     : Start job.
    2019-08-29 01:50:29.391  INFO 2781 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [step]
    2019-08-29 01:50:29.565  INFO 2781 --- [           main] c.g.h.a.batch.CorrectAgeProcessor        : Correct Alice.
    2019-08-29 01:50:29.609  INFO 2781 --- [           main] c.g.h.a.batch.CorrectAgeProcessor        : Correct Bob.
    2019-08-29 01:50:29.624  INFO 2781 --- [           main] c.g.h.a.batch.CorrectAgeProcessor        : Correct Carol.
    2019-08-29 01:50:29.651  INFO 2781 --- [           main] c.g.h.agecorrector.batch.JobListener     : Completed job.
    .
    .
    .
    
    ySQL로도 데이터를 확인해 보세요.실행하는 날8/29이지만 그날 태어난 사람의 나이를 갱신할 수 있다.
    mysql> select * from person;
    +----+-------+-----+------------+
    | id | name  | age | birthday   |
    +----+-------+-----+------------+
    |  1 | Alice |  24 | 1995-08-29 |
    |  2 | Bob   |  39 | 1980-08-29 |
    |  3 | Carol |  30 | 1989-08-29 |
    |  4 | Dave  |  23 | 1995-08-30 |
    +----+-------+-----+------------+
    

    총결산


    이후 크론 등에 접속하면 정기적으로 나이를 갱신할 수 있다.나는 SpringBatch와 MyBatis의 조합이 자바 프로그래머에게 이해하기 쉽고 처리하기 쉬운 프레임워크라고 생각한다.또한 이번에 설치되지 않은 편리한 기능 등 Spring Batch에 많이 있으니 꼭 사용하시기 바랍니다.

    참고 자료

  • https://spring.io/guides/gs/batch-processing/
  • https://terasoluna-batch.github.io/guideline/current/ja/
  • https://blog.mybatis.org/
  • 좋은 웹페이지 즐겨찾기