Spring Batch でメタテーブルを使いたくないのに使用されてしまう時はこうする

たいしたネタでもない上に詳細に機構を分かっているわけでもないのですが、たいしたことじゃないことほど一度ハマるとめちゃめちゃ時間を吸われるので、情報共有しておきます。

## 結論

さて、このようなタイトルの記事を読む方はきっと、[Stack Overflow](http://stackoverflow.com/questions/25077549/spring-batch-without-persisting-metadata-to-database)などを読み漁っても良い解決策が分からず、ハマり続けて悲しい気持ちになっている方だと思います。ので先に結論から申し上げると、

**DataSourceをBeanから抜いてください**。

それだけです。

## MapJobRepositoryFactoryBean では解決できない

Spring Batchはその実行状態を保存しておく機能を持っており、それが有効になっていると接続先のデータベースに勝手にテーブルを作ってなんのジョブのどのステップが実行されたかなどを管理してくれます。リカバリする時はこれを見てよい感じに再実行などしてくれるそうです。

しかしさほどややこしい機能もない時にはわざわざテーブルを生成してもらわなくても、コケたら全部実行しなおすよ、という気分になることがあるかと思います。そうするとむしろ勝手にテーブルができてしまうのが不都合になってきます。そして調べてみると[Spring Batchの公式ドキュメント](http://docs.spring.io/spring-batch/reference/html/configureJob.html#configuringJobRepository)で「In-Memory Repository」なんていう素敵な機能を見つけることになります。

そこには

```xml
<bean id="jobRepository"
  class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
    <property name="transactionManager" ref="transactionManager"/>
</bean>
```
(引用: [Spring Batch公式ドキュメント](http://docs.spring.io/spring-batch/reference/html/configureJob.html#inMemoryRepository))

と書いてあるので、Javaに置き換えて

```java
@Bean
public JobRepository getJobRepository() {
    return new MapJobRepositoryFactoryBean(new ResourcelessTransactionManager()).getObject();
}
```

なんて書くことになるかと思いますが**これでは動きません**。なんとか動かしても、メタテーブルは生成されるし実行情報は更新され続けます。

## 原因はDataSource

Springframeworkをお使いの方なら、Beanはデフォルトでオススメ設定が入っているが自分で定義したらそれで上書きされることはご存知かと思います。そして上の挙動はそれと相反する事象で混乱を招くかもしれません。

しかし大丈夫です。単に、メタテーブルが使用されてしまうことの原因が**Bean定義でJobRepositoryが決められているからではなかった**だけです。

原因は意外なところにあります。以下のJavaDocを読んでみてください。SpringBatchでジョブを定義する時によく使う`@EnableBatchProcessing`アノテーションのものです。

> If a user does not provide a DataSource within the context, a Map based [JobRepository](http://docs.spring.io/spring-batch/apidocs/org/springframework/batch/core/repository/JobRepository.html)  will be used.
引用元: [EnableBatchProcessing (Spring Batch 3.0.7.RELEASE API)](http://docs.spring.io/spring-batch/apidocs/)

これだけです。

あとはDataSourceをBean定義に入れなければ、自分で`MapJobRepositoryFactoryBean`などを定義しなくても勝手にメタテーブルは使われなくなります。
たとえば以下のように回避すれば良いでしょう。

```java
public DataSource driverManagerDataSource(String driver, String url, String userName, String password) {
    DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
    driverManagerDataSource.setDriverClassName(driver);
    driverManagerDataSource.setUrl(url);
    driverManagerDataSource.setUsername(userName);
    driverManagerDataSource.setPassword(password);
    return driverManagerDataSource;
}

@Bean
public NamedParameterJdbcTemplate namedParameterJdbcTemplate() {
    // TransactionManagerからDataSourceをもらう
    return new NamedParameterJdbcTemplate(dataSourceTransactionManager().getDataSource());
}

@Bean
public DataSourceTransactionManager dataSourceTransactionManager() {
    return new DataSourceTransactionManager(driverManagerDataSource("driverName", "url", "username", "password"));
}
```

分かってみればたいしたことではないですが、これで誰かが悲しい気持ちから救われれば嬉しいです。

## Refs

- [java - Spring-Batch without persisting metadata to database? - Stack Overflow](http://stackoverflow.com/questions/25077549/spring-batch-without-persisting-metadata-to-database)
- [Spring Batchの公式ドキュメント 4. Configuring and Running a Job](http://docs.spring.io/spring-batch/reference/html/configureJob.html#configuringJobRepository)
- [MapJobRepositoryFactoryBean (Spring Batch 3.0.7.RELEASE API)](http://docs.spring.io/spring-batch/apidocs/org/springframework/batch/core/repository/support/MapJobRepositoryFactoryBean.html)
- [EnableBatchProcessing (Spring Batch 3.0.7.RELEASE API)](http://docs.spring.io/spring-batch/apidocs/)