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.
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.
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:
- Replace
SpringBatchUtility.selectForCursor(...)
withSqlBuilder.select(...)
- Replace
render()
withrender(RenderingStrategies.MYBATIS3)
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:
- The
limit
andoffset
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
andMYBATIS_SPRING_BATCH_SKIPROWS
. You can use these values to make the code clearer, but again the values will be ignored at runtime. - 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. - 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.
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:
- Replace
SpringBatchUtility.selectForPaging(...)
withSqlBuilder.select(...)
- Add
limit()
,fetchFirst()
, andoffset()
method calls as appropriate for your query and database - Replace
render()
withrender(RenderingStrategies.SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY)
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