Skip to content

Latest commit

 

History

History
164 lines (132 loc) · 8.01 KB

springBatch.md

File metadata and controls

164 lines (132 loc) · 8.01 KB

Spring Batch Support

This library provides some utilities to make it easier to interact with the MyBatis Spring Batch support.

MyBatis Spring provides support for interacting with Spring Batch (see http://www.mybatis.org/spring/batch.html). This support consists of specialized implementations of Spring Batch's ItemReader and ItemWriter interfaces that have support for MyBatis mappers.

The ItemWriter implementation works with SQL generated by MyBatis Dynamic SQL with no modification needed.

The ItemReader implementations need special care. Those classes assume that all query parameters will be placed in a Map (as per usual when using multiple parameters in a query). MyBatis Dynamic SQL, by default, builds a parameter object that is intended to be the only parameter for a query. The library contains utilities for overcoming this difficulty.

Using MyBatisCursorItemReader

The MyBatisCursorItemReader class works with built-in support for cursor based queries in MyBatis. Queries of this type will read row by row and MyBatis will convert each result row to a result object without having to read the entire result set into memory. The normal rendering for MyBatis will work for queries using this reader, but special care must be taken to prepare the parameter values for use with this reader. See the following example:

@Bean
public MyBatisCursorItemReader<PersonRecord> reader(SqlSessionFactory sqlSessionFactory) {
    SelectStatementProvider selectStatement =  select(person.allColumns())
            .from(person)
            .where(lastName, isEqualTo("flintstone"))
            .build()
            .render(RenderingStrategies.MYBATIS3);

    MyBatisCursorItemReader<PersonRecord> reader = new MyBatisCursorItemReader<>();
    reader.setQueryId(PersonMapper.class.getName() + ".selectMany");
    reader.setSqlSessionFactory(sqlSessionFactory);
    reader.setParameterValues(SpringBatchUtility.toParameterValues(selectStatement));
    return reader;
}

Note the use of SpringBatchUtility.toParameterValues(...). This utility will set up the parameter Map correctly for the rendered statement, and for use with a library supplied @selectProvider. See the following for an example of the mapper method used for the query coded above:

@Mapper
public interface PersonMapper {

    @SelectProvider(type=SpringBatchProviderAdapter.class, method="select")
    @Results({
        @Result(column="id", property="id", id=true),
        @Result(column="first_name", property="firstName"),
        @Result(column="last_name", property="lastName")
    })
    List<PersonRecord> selectMany(Map<String, Object> parameterValues);
}

Note the use of the SpringBatchProviderAdapter - that adapter knows how to retrieve the rendered queries from the parameter map initialed in the method above.

Migrating from 1.x Support for MyBatisCursorItemReader

In version 1.x, the library supplied a special utility for creating a select statement as follows:

SelectStatementProvider selectStatement =  SpringBatchUtility.selectForCursor(person.allColumns())
        .from(person)
        .where(lastName, isEqualTo("flintstone"))
        .build()
        .render();

That utility method was limited in capability and has been removed. The new method described above allows the full capabilities of the library. To migrate, follow these steps:

  1. Replace SpringBatchUtility.selectForCursor(...) with SqlBuilder.select(...)
  2. Replace render() with render(RenderingStrategies.MYBATIS3)

Using MyBatisPagingItemReader

The MyBatisPagingItemReader class works with paging queries - queries that read rows in pages and process page by page rather than row by row. The normal rendering for MyBatis will work NOT for queries using this reader because MyBatis Spring support supplies specially named parameters for page size, offset, etc. So the query must be rendered properly to respond to these parameter values that are supplied at runtime. As with the other reader, special care must also be taken to prepare the parameter values for use with this reader. See the following example:

@Bean
public MyBatisPagingItemReader<PersonRecord> reader(SqlSessionFactory sqlSessionFactory) {
    SelectStatementProvider selectStatement =  select(person.allColumns())
            .from(person)
            .where(forPagingTest, isEqualTo(true))
            .orderBy(id)
            .limit(SpringBatchUtility.MYBATIS_SPRING_BATCH_PAGESIZE)
            .offset(SpringBatchUtility.MYBATIS_SPRING_BATCH_SKIPROWS)
            .build()
            .render(SpringBatchUtility.SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY);

    MyBatisPagingItemReader<PersonRecord> reader = new MyBatisPagingItemReader<>();
    reader.setQueryId(PersonMapper.class.getName() + ".selectMany");
    reader.setSqlSessionFactory(sqlSessionFactory);
    reader.setParameterValues(SpringBatchUtility.toParameterValues(selectStatement));
    reader.setPageSize(7);
    return reader;
}

Notice the following important items:

  1. The limit and offset methods in the query are used to set up paging support in the query. With MyBatis Spring batch support, the integration library will supply values for those parameters at runtime. Any values you code in the select statement will be ignored - only the values supplied by the library will be used. We supply two constants to make this clearer: MYBATIS_SPRING_BATCH_PAGESIZE and MYBATIS_SPRING_BATCH_SKIPROWS. You can use these values to make the code clearer, but again the values will be ignored at runtime.
  2. The query must be rendered with the SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY rendering strategy. This rendering strategy will render the query so that it will respond properly to the runtime values supplied for page size and skip rows.
  3. Note the use of SpringBatchUtility.toParameterValues(...). This utility will set up the parameter Map correctly for the rendered statement, and for use with a library supplied @selectProvider. See the following for an example of the mapper method used for the query coded above:
@Mapper
public interface PersonMapper {

    @SelectProvider(type=SpringBatchProviderAdapter.class, method="select")
    @Results({
        @Result(column="id", property="id", id=true),
        @Result(column="first_name", property="firstName"),
        @Result(column="last_name", property="lastName")
    })
    List<PersonRecord> selectMany(Map<String, Object> parameterValues);
}

Note the use of the SpringBatchProviderAdapter - that adapter knows how to retrieve the rendered queries from the parameter map initialed in the method above.

Migrating from 1.x Support for MyBatisPagingItemReader

In version 1.x, the library supplied a special utility for creating a select statement as follows:

SelectStatementProvider selectStatement =  SpringBatchUtility.selectForPaging(person.allColumns())
        .from(person)
        .where(forPagingTest, isEqualTo(true))
        .orderBy(id)
        .build()
        .render();

That utility method was very limited in capability and has been removed. The prior method only supported limit and offset based queries - which are not supported in all databases. The new method described above allows the full capabilities of the library to be used. To migrate, follow these steps:

  1. Replace SpringBatchUtility.selectForPaging(...) with SqlBuilder.select(...)
  2. Add limit(), fetchFirst(), and offset() method calls as appropriate for your query and database
  3. Replace render() with render(RenderingStrategies.SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY)

Complete Examples

The unit tests for MyBatis Dynamic SQL include a complete example of using MyBatis Spring Batch support using the MyBatis supplied reader as well as both types of MyBatis supplied writers. You can see the full example here: https://github.com/mybatis/mybatis-dynamic-sql/tree/master/src/test/java/examples/springbatch