SpringBatchを使ってみた（ただしバージョン4）

業務でSpringBatchを使用する機会があったので、その備忘録。
顧客の環境がJDK8を使用していたのでSpringBatchのバージョンは4を使用することになり、今後参考になるかはわからないが。

# メタテーブルが必要

SpringBatchを実行する際、RDBにメタテーブルを用意する必要がある。実行履歴などを記録しているものだ。
テーブル作成のスクリプト自体は`spring-batch-core`というjarファイルの中に用意されている。
この時はMySQLを使用した。

- jarファイル内のスクリプトファイルの場所
`/org/springframework/batch/core/schema-mysql.sql`

# プロパティファイル

`application.properties`に以下の設定を追加して使用した。

- `spring.batch.jdbc.initialize-schema=never`
メタテーブルをバッチの起動ごとに毎回作成し直すかの設定。neverはし直さない。

- spring.datasource.url=jdbc:mysql://host/schema
spring.datasource.username=user
spring.datasource.password=pass
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
MySQLの接続設定

- `spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl`
キャメルケースを勝手にスネークケースに読み替えてしまうため、読み替えないために設定をしている。

# クラス
ここでは便宜上とHelloWorldとする

### HelloWorldBatchApplication
SpringBootでお約束のApplication
```java
@SpringBootApplication
@EnableScheduling
public class HelloWorldBatchApplication {

	public static void main(String[] args) {
		SpringApplication.run(HelloWorldBatchApplication.class, args);
	}

}
```
- `@EnableScheduling` スケジュールを有効にするアノテーション

### HelloWorldBatchConfig
実行するジョブとそのステップを定義する。
```java
@Configuration
@EnableBatchProcessing
public class HelloWorldBatchConfig {

	@Autowired
	private JobBuilderFactory jobBuilderFactory;

	@Autowired
	private StepBuilderFactory stepBuilderFactory;

	@Autowired
	private HelloWorldTasklet helloWorldTasklet;

	/**
	 * HelloWorldジョブ
	 * @param helloWorldStep
	 * @return
	 */
	@Bean(name="helloWorldJob")
	public Job helloWorldJob(Step helloWorldStep) {
		return jobBuilderFactory.get("helloWorldJob") //Job名を指定
				.incrementer(new RunIdIncrementer())
				.flow(helloWorldStep) //実行するStepを指定
				.end()
				.build();
	}

	/**
	 * HelloWorldのステップ
	 * @param helloWorldStep
	 * @return
	 */
	@Bean
	public Step helloWorldStep() {
		return stepBuilderFactory.get("helloWorldStep") //Step名を指定
				.tasklet(helloWorldTasklet) //実行するTaskletを指定
				.build();
	}
}

```
- JOBを定義するメソッド内にてincrementerで実行IDをインクリメントしている。これをしないと一つのJOBで同一の実行IDとなるので、一度実行した同じJOBを再度実行しても、すでに実行済みとなって処理が終了してしまうことが起きた。

### ScheduledJobLauncher
ジョブのスケジュールを管理するクラス
```java
@Component
public class ScheduledJobLauncher {

	@Autowired
	private JobLauncher jobLauncher;

	@Autowired
	private Job helloWorldJob;

	@Scheduled(cron = "*/5 * * * * *")
	public void launchJob() throws Exception {
		JobParameters jobParameters = new JobParametersBuilder();
		jobLauncher.run(helloWorldJob, jobParameters);
	}

```
- SpringBatchでは秒までの設定が可能であるため、cron形式でスケジュールを設定する場合Linuxの5個ではなく6個の指定箇所がある。左端が秒。この例では5秒毎に実行される
- `HelloWorldBatchConfig`のBeanアノテーションで定義された`helloWorldJob`を指定している
- もしHelloWorldBatchConfigで.incrementer(new RunIdIncrementer())を使わずに実行履歴をユニークにしたい場合は、以下のようにパラメータを指定してあげると、IDのインクリメントの代わりにTimestampがIDとして使用される
```java
JobParameters jobParameters = new JobParametersBuilder()
        .addLong("timestamp", System.currentTimeMillis())
        .toJobParameters();
```


### HelloWorldTasklet
ステップの中身のクラス。実際のバッチの処理はTaskletに書く。
```java
@Component
@StepScope
public class HelloWorldTasklet implements Tasklet {

	/**
	 * HelloWorldジョブのtasklet
	 */
	@Override
	public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        System.out.println("Hello, World!");
        return RepeatStatus.FINISHED;
	}

}
```

# その他
ここでは記載しなかったが、メタテーブルにデータがどんどん追加されていってしまうので、定期的にレコードを削除するバッチも作成した（[参照記事](https://medium.com/@daneitian/spring-batch%E3%81%AE%E3%83%A1%E3%82%BF%E3%83%87%E3%83%BC%E3%82%BF%E5%89%8A%E9%99%A4-2cb03e75a756)）

以上