JdbcPagingItemReader/JdbcCursorItemReader/JdbcBatchItemWriterの実装サンプル

# はじめに
Jdbc系のItemReader/ItemWriterを利用して簡単なバッチアプリを作ってみたので、JdbcPagingItemReader/JdbcCursorItemReader/JdbcBatchItemWriterの実装例をまとめてみました。
Spring Bacthのバージョンは4.0.1です。

# サンプルAPの仕様
単純なデータをコピーするだけのバッチAPです。
テーブルsampleのデータを取得し、同じ構造のテーブルsample_subに出力するだけです。サンプルAPではH2DBをDBMSとして利用します。
テーブル定義は以下の通りです。

```sql:
CREATE TABLE IF NOT EXISTS sample (
    id VARCHAR(4),
    parameter1 VARCHAR(20),
    parameter2 VARCHAR(20),
    status VARCHAR(10),
    last_update_timestamp TIMESTAMP,
    PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS sample_sub (
    id VARCHAR(4),
    parameter1 VARCHAR(20),
    parameter2 VARCHAR(20),
    status VARCHAR(10),
    last_update_timestamp TIMESTAMP,
    PRIMARY KEY(id)
);
```


# 実装サンプル
## JdbcPagingItemReader
JdbcPagingItemReaderを実装する場合、queryProviderを設定する必要があり、実装方法はSqlPagingQueryProviderFactoryBeanを利用するパターンと、各DBMSごとに提供されているPagingQueryProviderを利用するパターンの2つあります。
(サンプルAPではH2DBをりようしているため、H2PagingQueryProviderを利用します。利用するDBMSによって指定するクラスが異なります。PagingQueryProviderのクラス一覧は[こちら](https://docs.spring.io/spring-batch/4.0.x/api/index.html)参照。)


### SqlPagingQueryProviderFactoryBeanの利用例
```java:JdbcPagingItemReader実装サンプル1

@Autowired
public DataSource dataSource;

@Bean
public SqlPagingQueryProviderFactoryBean queryProvider() {

    SqlPagingQueryProviderFactoryBean provider = new SqlPagingQueryProviderFactoryBean();
    provider.setDataSource(dataSource);
    provider.setSelectClause("SELECT id, parameter1, parameter2, status, last_update_timestamp");
    provider.setFromClause("FROM sample");     
    provider.setWhereClause("WHERE status = :status");
    provider.setSortKey("id");

    return provider;
}

@Bean
public JdbcPagingItemReader jdbcPagingItemReader() throws Exception {

    Map<String, Object> parameterValues = new HashMap();
    parameterValues.put("status", "A");

    return new JdbcPagingItemReaderBuilder<Sample>()
            .name("jdbcPagingItemReader")
            .dataSource(dataSource)
            .queryProvider(queryProvider().getObject())
            .parameterValues(parameterValues)
            .rowMapper(new SampleRowMapper())
            .pageSize(1000)
            .build();
}
```

### H2PagingQueryProviderの利用例
```java:JdbcPagingItemReader実装サンプル2
@Autowired
public DataSource dataSource;

@Bean
public H2PagingQueryProvider h2QueryProvider(Map sortKeys) {

    H2PagingQueryProvider h2Provider = new H2PagingQueryProvider();
    h2Provider.setSelectClause("SELECT id, parameter1, parameter2, status, last_update_timestamp");
    h2Provider.setFromClause("FROM sample");
    h2Provider.setWhereClause("WHERE status = :status");
    h2Provider.setSortKeys(sortKeys);

    return h2Provider;
}

@Bean
public JdbcPagingItemReader jdbcPagingItemReader() {

    Map<String, Order> sortKeys = new HashMap(1);
    sortKeys.put("id", Order.ASCENDING);

    Map<String, Object> parameterValues = new HashMap();
    parameterValues.put("status", "A");

    return new JdbcPagingItemReaderBuilder<Sample>()
            .name("jdbcPagingItemReader")
            .dataSource(dataSource)
            .queryProvider(h2QueryProvider(sortKeys))
            .parameterValues(parameterValues)
            .rowMapper(new SampleRowMapper())
            .pageSize(1000)
            .build();
}
```


## JdbcCursorItemReader
```java:JdbcCursorItemReader実装サンプル
@Autowired
public DataSource dataSource;

@Bean
public JdbcCursorItemReader jdbcCursorItemReader() {

    String status = "A";

    return new JdbcCursorItemReaderBuilder<Sample>()
            .dataSource(dataSource)
            .name("jdbcCursorItemReader")
            .sql("SELECT id, parameter1, parameter2, status, last_update_timestamp FROM sample WHERE status = '" + status + "';")
            .rowMapper(new SampleRowMapper())
            .build();
}
```


## JdbcBatchItemWriter
```java:JdbcBatchItemWriter実装サンプル
@Bean
public JdbcBatchItemWriter jdbcBatchItemWriter() {
    return new JdbcBatchItemWriterBuilder<Sample>()
            .dataSource(dataSource)
            .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Sample>())
            .sql("INSERT INTO sample_sub (id, parameter1, parameter2, status, last_update_timestamp) VALUES (:id, :parameter1, :parameter2, :status, :lastUpdateTimestamp);")
            .build();
}

```

## その他クラス
ItemReader/ItemWriterで参照するその他クラスはこちらです。

```java:Sample
public class Sample {

    private String id;

    private String parameter1;

    private String parameter2;

    private String status;

    private Timestamp lastUpdateTimestamp;

    /*setter・getterは省略*/

}
```
```java:SampleRowMapper
@Component
public class SampleRowMapper implements RowMapper {

    @Override
    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
        Sample sample = new Sample();

        sample.setId(rs.getString("id"));
        sample.setParameter1(rs.getString("parameter1"));
        sample.setParameter2(rs.getString("parameter2"));
        sample.setStatus(rs.getString("status"));
        sample.setLastUpdateTimestamp(rs.getTimestamp("last_update_timestamp"));
        return sample;
    }
}

```
# おまけ (Spring Batch 3.0.xでの実装)
Spring Batch 4.0.xの公式ドキュメントの実装例では、Builderを利用してItemReader/ItemWriterを実装していますが、Spring Batch 3.0.xではBuilderが提供されていないため、今回の実装例は利用できません。
Spring Batch 3.0.xを利用する場合は、Builderを利用せずに実装する必要があります。

## JdbcPagingItemReader
```java:JdbcPagingItemReader実装サンプル3
@Bean
public ItemReader<Sample> jdbcPagingItemReader() throws Exception {

    Map<String, Object> parameterValues = new HashMap();
    parameterValues.put("status", "A");

    JdbcPagingItemReader reader = new JdbcPagingItemReader();
    reader.setDataSource(dataSource);
    reader.setPageSize(1000);
    reader.setRowMapper(new SampleRowMapper());
    reader.setParameterValues(parameterValues);
    reader.setQueryProvider(queryProvider().getObject());

    return reader;
}
```

## JdbcCursorItemReader
```java:JdbcCursorItemReader実装サンプル2
@Bean
public ItemReader<Sample> jdbcCursorItemReader() {

    String status = "A";

    JdbcCursorItemReader reader = new JdbcCursorItemReader();
    reader.setDataSource(dataSource);
    reader.setSql("SELECT id, parameter1, parameter2, status, last_update_timestamp FROM sample WHERE status = '" + status + "';");
    reader.setRowMapper(new SampleRowMapper());
    return reader;
}
```
## JdbcBatchItemWriter
```java:JdbcBatchItemWriter実装サンプル2
@Bean
public ItemWriter<Sample> jdbcBatchItemWriter(){
    JdbcBatchItemWriter writer = new JdbcBatchItemWriter();
    writer.setDataSource(dataSource);
    writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Sample>());
    writer.setSql("INSERT INTO sample_sub (id, parameter1, parameter2, status, last_update_timestamp) VALUES (:id, :parameter1, :parameter2, :status, :lastUpdateTimestamp);");
    return writer;
}
```