簡単なSpring Batchのサンプル

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
【4/18開催】VSCode Dev Containersで楽々開発環境構築祭り〜Python/Reactなどなど〜
Visual Studio Codeの拡張機能であるDev Containersを使ってReactとかPythonとかSpring Bootとかの開発環境をラクチンで構築する方法を紹介するイベントです。
https://tech-lab.connpass.com/event/311864/

概要

Spring BatchJobという単位でバッチ処理を行います。 Jobは複数のStepを順番に実行します。 Stepには入力、処理、出力をひとまとまりに実行するChankと自由に処理を実行できるTaskletというふたつの種類があります。 0001_Jobの構成 多くのバッチ処理はどこからかデータを読み込み加工してどこかへ出力するという形になります。 データベースに出力するChankでは出力をトランザクションで保護します。 途中でエラーが発生した場合はロールバックされ処理が正常に終了した場合はコミットされます。 データベースのテーブルからデータを読み込み別テーブルに出力する最も簡単なバッチ処理を実装します。 このサンプルはSpring Batchの構造を紹介する目的で作成しています。 行っている処理に意味はありません。 サンプルではMySQLを使用していますがJDBCで接続できるデータベースであれば何でも構いません。

データベースの作成

次のコマンドを使用してデータベースを作成します。 ついでにテスト用のユーザーも作成します。

CREATE DATABASE sample_db;

CREATE USER sample_user IDENTIFIED BY 'sample_password';
GRANT ALL PRIVILEGES ON sample_db.* TO sample_user;

mysqlコマンドでデータベースに接続します。

mysql -u sample_user -p sample_db

次のSQLを用いてテーブルを作成します。

CREATE TABLE IF NOT EXISTS source_item (
    name VARCHAR(100) NOT NULL PRIMARY KEY,
    value VARCHAR(200) NOT NULL,
    valid BOOLEAN
);

CREATE TABLE IF NOT EXISTS target_item (
    name VARCHAR(100) NOT NULL PRIMARY KEY,
    value VARCHAR(200) NOT NULL
);

CREATE TABLE IF NOT EXISTS large_item (
    name VARCHAR(100) NOT NULL PRIMARY KEY,
    value VARCHAR(200) NOT NULL
);

Step-1

Step-1source_itemテーブルから読み込みvalidtrueのレコードだけをtarget_itemに出力します。

ItemReader

source_itemから読み込むItemReaderを実装します。 処理の大部分はフレームワークが行うのでプログラムではエンティティとリポジトリを実装します。

  • SourceItemEntity.java
    package com.sios.ex.springbatch;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    import lombok.Data;
    import lombok.Getter;
    
    @Data
    @Entity
    @Table(name = "source_item")
    public class SourceItemEntity {
    
    	@Id
    	@Column(name = "name", nullable = false)
    	@Getter
    	private String name;
    
    	@Column(name = "value", nullable = false)
    	@Getter
    	private String value;
    
    	@Column(name = "valid", nullable = false)
    	@Getter
    	private boolean valid;
    
    	public SourceItemEntity(
    			String name,
    			String value,
    			boolean valid) {
    		this.name = name;
    		this.value = value;
    		this.valid = valid;
    	}
    
    }
    
  • SourceItemRepository.java

    package com.sios.ex.springbatch;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public interface SourceItemRepository extends JpaRepository<SourceItemEntity, String> {
    
    }
    

作成したエンティティとリポジトリを用いてItemReaderを組み立てます。

  • SpringBatchSample1Configuration.javaより抜粋
      @Autowired
      private SourceItemRepository sourceItemRepository;
    
      ・
      ・
      ・
    
    @Bean
      public ItemReader<SourceItemEntity> sourceItemReader() {
        RepositoryItemReader<SourceItemEntity> reader = new RepositoryItemReader<>();
        reader.setRepository(sourceItemRepository);
        reader.setMethodName("findAll");
        Map<String, Direction> sort = new HashMap<>();
        sort.put("name", Direction.ASC);
        reader.setSort(sort);
        return reader;
      }
    

ItemProcessor

ItemProcessorsource_itemvalidtrueのレコードだけをTargetItemEntityのオブジェクトに変換して返します。 target_itemに出力しない場合はnullを返します。

  • TargetItemProcessor.java
    package com.sios.ex.springbatch;
    
    import org.springframework.batch.item.ItemProcessor;
    
    public class TargetItemProcessor implements ItemProcessor<SourceItemEntity, TargetItemEntity> {
    
    	@Override
    	public TargetItemEntity process(SourceItemEntity item) throws Exception {
    		if (item.isValid()) {
    			return new TargetItemEntity(item.getName(), item.getValue());
    		} else {
    			return null;
    		}
    	}
    
    }
    
  • SpringBatchSample1Configuration.javaより抜粋

      @Bean
      public TargetItemProcessor targetItemProcessor() {
        return new TargetItemProcessor();
      }
    

ItemWriter

target_itemへ出力するItemWriterを実装します。 処理の大部分はフレームワークが行うのでプログラムではエンティティとリポジトリを実装します。

  • TargetItemEntity.java
    package com.sios.ex.springbatch;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    import lombok.Data;
    import lombok.Getter;
    
    @Data
    @Entity
    @Table(name = "target_item")
    public class TargetItemEntity {
    
    	@Id
    	@Column(name = "name", nullable = false)
    	@Getter
    	private String name;
    
    	@Column(name = "value", nullable = false)
    	@Getter
    	private String value;
    
    	public TargetItemEntity(
    			String name,
    			String value) {
    		this.name = name;
    		this.value = value;
    	}
    }
    
  • TargetItemRepository.java

    package com.sios.ex.springbatch;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public interface TargetItemRepository extends JpaRepository<TargetItemEntity, String> {
    
    }
    
  • SpringBatchSample1Configuration.javaより抜粋

      @Autowired
      private TargetItemRepository targetItemRepository;
    
        ・
        ・
        ・
    
      @Bean
      public ItemWriter<TargetItemEntity> targetItemWriter() {
        RepositoryItemWriter<TargetItemEntity> writer = new RepositoryItemWriter<>();
        writer.setRepository(targetItemRepository);
        writer.setMethodName("save");
        return writer;
      }
    

Stepの構築

  • SpringBatchSample1Configuration.javaより抜粋
      @Autowired
      private StepBuilderFactory stepBuilderFactory;
    
      ・
      ・
      ・
    
      @Bean
      public Step sampleBatch1Step1() {
    		return stepBuilderFactory.get("sampleBatch1Step1")
    				.<SourceItemEntity, TargetItemEntity> chunk(Integer.MAX_VALUE)
    				.reader(sourceItemReader())
    				.processor(targetItemProcessor())
    				.writer(targetItemWriter())
    				.build();
    	}
    

Step-2

Step-2target_itemテーブルから読み込み英字を大文字に変換してlarge_itemテーブルに出力します。

ItemReader

Step-1ItemReaderのエンティティとリポジトリが変わっただけなので省略します。

ItemProcessor

受け取ったTargetItemEntitynamevalueの値を大文字に変換してLargetItemEntityのオブジェクトを生成して返します。

package com.sios.ex.springbatch;

import org.springframework.batch.item.ItemProcessor;

public class LargeItemProcessor implements ItemProcessor<TargetItemEntity, LargeItemEntity> {

	@Override
	public LargeItemEntity process(TargetItemEntity item) throws Exception {
		return new LargeItemEntity(
				item.getName().toUpperCase(),
				item.getValue().toUpperCase());
	}

}
* SpringBatchSample1Configuration.javaより抜粋
  @Bean
  public LargeItemProcessor largeItemProcessor() {
    return new LargeItemProcessor();
  }

ItemWriter

Step-1ItemWriterのエンティティとリポジトリが変わっただけなので省略します。

Jobの組み立て

Step-1Step-2のふたつのStepを持つJobを構築します。

  • SpringBatchSample1Configuration.javaより抜粋
      @Autowired
      private JobBuilderFactory jobBuilderFactory;
    
      ・
      ・
      ・
    
      @Bean
      public Job sampleBatch1Job() {
        return jobBuilderFactory.get("sampleBatch1Job")
            .incrementer(new RunIdIncrementer())
            .flow(sampleBatch1Step1())
            .next(sampleBatch1Step2())
            .end()
            .build();
      }
    

Jobの実行

最後にJobを実行するメインクラスを作成します。 SpringBatchSample1Application#mainを呼び出すとバッチ処理を行います。

package com.sios.ex.springbatch;

import org.springframework.batch.core.launch.support.CommandLineJobRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class SpringBatchSample1Application implements CommandLineRunner {

	public static void main(String[] args) {
		SpringApplication application = new SpringApplication(SpringBatchSample1Application.class);
		application.setWebApplicationType(WebApplicationType.NONE);
		ApplicationContext context = application.run();
		SpringApplication.exit(context);
	}

	@Override
	public void run(String... args) throws Exception {
		CommandLineJobRunner.main(new String[] {
				"com.sios.ex.springbatch.SpringBatchSample1Configuration",
				"sampleBatch1Job"});
	}

}

ソースファイル一式は次のリンクからダウンロードできます。 ※ ソースファイル一式

アバター画像
About サイオステクノロジーの中の人 5 Articles
サイオステクノロジーで働く中の人です。
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

2人がこの投稿は役に立ったと言っています。


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

1 Comment

  1. ご共有ありがとうございました。グーグルから検索し、RepositoryItemWriterについて大変助かりました。

ちゃん へ返信する コメントをキャンセル

Your email address will not be published.


*


質問はこちら 閉じる