概要
Spring BatchはJobという単位でバッチ処理を行います。 Jobは複数のStepを順番に実行します。 Stepには入力、処理、出力をひとまとまりに実行するChankと自由に処理を実行できるTaskletというふたつの種類があります。 多くのバッチ処理はどこからかデータを読み込み加工してどこかへ出力するという形になります。 データベースに出力する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-1はsource_itemテーブルから読み込みvalidがtrueのレコードだけを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
ItemProcessorはsource_itemのvalidがtrueのレコードだけを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-2はtarget_itemテーブルから読み込み英字を大文字に変換してlarge_itemテーブルに出力します。
ItemReader
Step-1のItemReaderのエンティティとリポジトリが変わっただけなので省略します。
ItemProcessor
受け取ったTargetItemEntityのnameとvalueの値を大文字に変換して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-1のItemWriterのエンティティとリポジトリが変わっただけなので省略します。
Jobの組み立て
Step-1とStep-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"}); } }ソースファイル一式は次のリンクからダウンロードできます。 ※ ソースファイル一式
ご共有ありがとうございました。グーグルから検索し、RepositoryItemWriterについて大変助かりました。