Skip to content

Commit 3ade4fe

Browse files
committed
Documentation
1 parent 4e8bf74 commit 3ade4fe

File tree

2 files changed

+116
-68
lines changed

2 files changed

+116
-68
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ worked to make these changes as minimal as possible.
1212

1313
**Potentially Breaking Changes:**
1414

15+
- If you use this library with MyBatis' Spring Batch integration, you will need to make changes as we have
16+
refactored that support to be more flexible. Please see the
17+
[Spring Batch](https://mybatis.org/mybatis-dynamic-sql/docs/springBatch.html) documentation page to see the new usage
18+
details.
1519
- If you have created any custom implementations of `SortSpecification`, you will need to update those
1620
implementations due to a new rendering strategy for ORDER BY phrases. The old methods `isDescending` and `orderByName`
1721
are removed in favor of a new method `renderForOrderBy`

src/site/markdown/docs/springBatch.md

Lines changed: 112 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,144 @@
11
# Spring Batch Support
22
This library provides some utilities to make it easier to interact with the MyBatis Spring Batch support.
33

4-
## The Problem
4+
MyBatis Spring provides support for interacting with Spring Batch (see
5+
[http://www.mybatis.org/spring/batch.html](http://www.mybatis.org/spring/batch.html)). This support consists of
6+
specialized implementations of Spring Batch's `ItemReader` and `ItemWriter` interfaces that have support for MyBatis
7+
mappers.
58

6-
MyBatis Spring support provides utility classes for interacting with Spring Batch (see [http://www.mybatis.org/spring/batch.html](http://www.mybatis.org/spring/batch.html)). These classes are specialized implementations of Spring Batch's `ItemReader` and `ItemWriter` interfaces that have support for MyBatis mappers.
9+
The `ItemWriter` implementation works with SQL generated by MyBatis Dynamic SQL with no modification needed.
710

8-
The `ItemWriter` implementations work with SQL generated by MyBatis Dynamic SQL with no modification needed.
11+
The `ItemReader` implementations need special care. Those classes assume that all query parameters will be placed in a
12+
Map (as per usual when using multiple parameters in a query). MyBatis Dynamic SQL, by default, builds a parameter
13+
object that is intended to be the only parameter for a query. The library contains utilities for overcoming this
14+
difficulty.
915

10-
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 should be the only parameter in a query and will not work when placed in a Map of parameters.
16+
## Using MyBatisCursorItemReader
1117

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

14-
The solution involves these steps:
15-
16-
1. The SQL must be rendered such that the parameter markers are aware of the enclosing parameter Map in the `ItemReader`
17-
1. The `SelectStatementProvider` must be placed in the `ItemReader` parameter Map with a known key.
18-
1. The `@SelectProvider` must be configured to be aware of the enclosing parameter Map
19-
20-
MyBatis Dynamic SQL provides utilities for each of these requirements. Each utility uses a shared Map key for consistency.
21-
22-
## Spring Batch Item Readers
23-
24-
MyBatis Spring support supplies two implementations of the `ItemReader` interface:
25-
26-
1. `org.mybatis.spring.batch.MyBatisCursorItemReader` - for queries that can be efficiently processed through a single select statement and a cursor
27-
1. `org.mybatis.spring.batch.MyBatisPagingItemReader` - for queries that should be processed as a series of paged selects. Note that MyBatis does not provide any native support for paged queries - it is up to the user to write SQL for paging. The `MyBatisPagingItemWriter` simply makes properties available that specify which page should be read currently.
28-
29-
MyBatis Dynamic SQL supplies specialized select statements that will render properly for the different implementations of `ItemReader`:
30-
31-
1. `SpringBatchUtility.selectForCursor(...)` will create a select statement that is appropriate for the `MyBatisCursorItemReader` - a single select statement that will be read with a cursor
32-
1. `SpringBatchUtility.selectForPaging(...)` will create a select statement that is appropriate for the `MyBatisPagingItemReader` - a select statement that will be called multiple times - one for each page as configured on the batch job.
33-
34-
**Very Important:** The paging implementation will only work for databases that support limit and offset in select statements. Fortunately, most databases do support this - with the notable exception of Oracle.
35-
36-
37-
### Rendering for Cursor
23+
```java
24+
@Bean
25+
public MyBatisCursorItemReader<PersonRecord> reader(SqlSessionFactory sqlSessionFactory) {
26+
SelectStatementProvider selectStatement = select(person.allColumns())
27+
.from(person)
28+
.where(lastName, isEqualTo("flintstone"))
29+
.build()
30+
.render(RenderingStrategies.MYBATIS3);
31+
32+
MyBatisCursorItemReader<PersonRecord> reader = new MyBatisCursorItemReader<>();
33+
reader.setQueryId(PersonMapper.class.getName() + ".selectMany");
34+
reader.setSqlSessionFactory(sqlSessionFactory);
35+
reader.setParameterValues(SpringBatchUtility.toParameterValues(selectStatement));
36+
return reader;
37+
}
38+
```
3839

39-
Queries intended for the `MyBatisCursorItemReader` should be rendered as follows:
40+
Note the use of `SpringBatchUtility.toParameterValues(...)`. This utility will set up the parameter Map correctly for the
41+
rendered statement, and for use with a library supplied `@selectProvider`. See the following for an example of the mapper
42+
method used for the query coded above:
4043

4144
```java
42-
SelectStatementProvider selectStatement = SpringBatchUtility.selectForCursor(person.allColumns())
43-
.from(person)
44-
.where(lastName, isEqualTo("flintstone"))
45-
.build()
46-
.render(); // renders for MyBatisCursorItemReader
45+
@Mapper
46+
public interface PersonMapper {
47+
48+
@SelectProvider(type=SpringBatchProviderAdapter.class, method="select")
49+
@Results({
50+
@Result(column="id", property="id", id=true),
51+
@Result(column="first_name", property="firstName"),
52+
@Result(column="last_name", property="lastName")
53+
})
54+
List<PersonRecord> selectMany(Map<String, Object> parameterValues);
55+
}
4756
```
4857

49-
### Rendering for Paging
58+
Note the use of the `SpringBatchProviderAdapter` - that adapter knows how to retrieve the rendered queries from the
59+
parameter map initialed in the method above.
5060

51-
Queries intended for the `MyBatisPagingItemReader` should be rendered as follows:
61+
### Migrating from 1.x Support for MyBatisCursorItemReader
62+
63+
In version 1.x, the library supplied a special utility for creating a select statement as follows:
5264

5365
```java
54-
SelectStatementProvider selectStatement = SpringBatchUtility.selectForPaging(person.allColumns())
55-
.from(person)
56-
.where(lastName, isEqualTo("flintstone"))
57-
.build()
58-
.render(); // renders for MyBatisPagingItemReader
66+
SelectStatementProvider selectStatement = SpringBatchUtility.selectForCursor(person.allColumns())
67+
.from(person)
68+
.where(lastName, isEqualTo("flintstone"))
69+
.build()
70+
.render();
5971
```
6072

61-
## Creating the Parameter Map
73+
That utility method was limited in capability. The new method allows the full capabilities of the library. To migrate,
74+
follow these steps:
6275

63-
The `SpringBatchUtility` provides a method to create the parameter values Map needed by the MyBatis Spring `ItemReader` implementations. It can be used as follows:
76+
1. Replace `SpringBatchUtility.selectForCursor(...)` with `SqlBuilder.select(...)`
77+
2. Replace `render()` with `render(RenderingStrategies.MYBATIS3)`
6478

65-
For cursor based queries...
79+
## Using MyBatisPagingItemReader
6680

67-
```java
68-
MyBatisCursorItemReader<Person> reader = new MyBatisCursorItemReader<>();
69-
reader.setQueryId(PersonMapper.class.getName() + ".selectMany");
70-
reader.setSqlSessionFactory(sqlSessionFactory);
71-
reader.setParameterValues(SpringBatchUtility.toParameterValues(selectStatement)); // create parameter map
72-
```
73-
For paging based queries...
81+
The `MyBatisPagingItemReader` class works with paging queries - queries that read rows in pages and process page by page
82+
rather than row by row. The normal rendering for MyBatis will work NOT for queries using this reader because MyBatis
83+
Spring support supplies specially named parameters for page size, offset, etc. So the query must be rendered properly
84+
to respond to these parameter values that are supplied at runtime. As with the other reader, special care
85+
must also be taken to prepare the parameter values for use with this reader. See the following example:
7486

7587
```java
76-
MyBatisPagingItemReader<Person> reader = new MyBatisPagingItemReader<>();
77-
reader.setQueryId(PersonMapper.class.getName() + ".selectMany");
78-
reader.setSqlSessionFactory(sqlSessionFactory);
79-
reader.setPageSize(7);
80-
reader.setParameterValues(SpringBatchUtility.toParameterValues(selectStatement)); // create parameter map
88+
@Bean
89+
public MyBatisPagingItemReader<PersonRecord> reader(SqlSessionFactory sqlSessionFactory) {
90+
SelectStatementProvider selectStatement = select(person.allColumns())
91+
.from(person)
92+
.where(forPagingTest, isEqualTo(true))
93+
.orderBy(id)
94+
.limit(SpringBatchUtility.MYBATIS_SPRING_BATCH_PAGESIZE)
95+
.offset(SpringBatchUtility.MYBATIS_SPRING_BATCH_SKIPROWS)
96+
.build()
97+
.render(SpringBatchUtility.SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY);
98+
99+
MyBatisPagingItemReader<PersonRecord> reader = new MyBatisPagingItemReader<>();
100+
reader.setQueryId(PersonMapper.class.getName() + ".selectMany");
101+
reader.setSqlSessionFactory(sqlSessionFactory);
102+
reader.setParameterValues(SpringBatchUtility.toParameterValues(selectStatement));
103+
reader.setPageSize(7);
104+
return reader;
105+
}
81106
```
107+
Notice the following important items:
82108

109+
1. The `limit` and `offset` methods in the query are used to set up paging support in the query. With MyBatis Spring
110+
batch support, the integration library will supply values for those parameters at runtime. Any values you code in the
111+
select statement will be ignored - only the values supplied by the library will be used. We supply two constants
112+
to make this clearer: `MYBATIS_SPRING_BATCH_PAGESIZE` and `MYBATIS_SPRING_BATCH_SKIPROWS`. You can use these values
113+
to make the code clearer, but again the values will be ignored at runtime.
114+
2. The query must be rendered with the `SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY` rendering strategy. This
115+
rendering strategy will render the query so that it will respond properly to the runtime values supplied for page size
116+
and skip rows.
83117

84-
## Specialized @SelectProvider Adapter
118+
### Migrating from 1.x Support for MyBatisPagingItemReader
85119

86-
MyBatis mapper methods should be configured to use the specialized `@SelectProvider` adapter as follows:
120+
In version 1.x, the library supplied a special utility for creating a select statement as follows:
87121

88122
```java
89-
@SelectProvider(type=SpringBatchProviderAdapter.class, method="select") // use the Spring batch adapter
90-
@Results({
91-
@Result(column="id", property="id", id=true),
92-
@Result(column="first_name", property="firstName"),
93-
@Result(column="last_name", property="lastName")
94-
})
95-
List<Person> selectMany(Map<String, Object> parameterValues);
123+
SelectStatementProvider selectStatement = SpringBatchUtility.selectForPaging(person.allColumns())
124+
.from(person)
125+
.where(forPagingTest, isEqualTo(true))
126+
.orderBy(id)
127+
.build()
128+
.render();
96129
```
97130

98-
## Complete Example
131+
That utility method was very limited in capability. It only supported limit and offset based queries - which are not
132+
supported in all databases. The new method allows the full capabilities of the library. To migrate,
133+
follow these steps:
134+
135+
1. Replace `SpringBatchUtility.selectForPaging(...)` with `SqlBuilder.select(...)`
136+
2. Add `limit()`, `fetchFirst()`, and `offset()` method calls as appropriate for your query and database
137+
3. Replace `render()` with `render(RenderingStrategies.SPRING_BATCH_PAGING_ITEM_READER_RENDERING_STRATEGY)`
138+
139+
140+
## Complete Examples
99141

100-
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](https://github.com/mybatis/mybatis-dynamic-sql/tree/master/src/test/java/examples/springbatch)
142+
The unit tests for MyBatis Dynamic SQL include a complete example of using MyBatis Spring Batch support using the
143+
MyBatis supplied reader as well as both types of MyBatis supplied writers. You can see the full example
144+
here: [https://github.com/mybatis/mybatis-dynamic-sql/tree/master/src/test/java/examples/springbatch](https://github.com/mybatis/mybatis-dynamic-sql/tree/master/src/test/java/examples/springbatch)

0 commit comments

Comments
 (0)