View Javadoc
1   /*
2    * Copyright 2010-2025 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.mybatis.spring.batch;
17  
18  import static org.springframework.util.Assert.notNull;
19  import static org.springframework.util.ClassUtils.getShortName;
20  
21  import java.util.HashMap;
22  import java.util.Map;
23  import java.util.Optional;
24  import java.util.concurrent.CopyOnWriteArrayList;
25  import java.util.function.Supplier;
26  
27  import org.apache.ibatis.session.ExecutorType;
28  import org.apache.ibatis.session.SqlSession;
29  import org.apache.ibatis.session.SqlSessionFactory;
30  import org.mybatis.spring.SqlSessionTemplate;
31  import org.springframework.batch.infrastructure.item.database.AbstractPagingItemReader;
32  
33  /**
34   * {@code org.springframework.batch.infrastructure.item.ItemReader} for reading database records using MyBatis in a
35   * paging fashion.
36   * <p>
37   * Provided to facilitate the migration from Spring-Batch iBATIS 2 page item readers to MyBatis 3.
38   *
39   * @author Eduardo Macarron
40   *
41   * @param <T>
42   *          the generic type
43   *
44   * @since 1.1.0
45   */
46  public class MyBatisPagingItemReader<T> extends AbstractPagingItemReader<T> {
47  
48    private String queryId;
49  
50    private SqlSessionFactory sqlSessionFactory;
51  
52    private SqlSessionTemplate sqlSessionTemplate;
53  
54    private Map<String, Object> parameterValues;
55  
56    private Supplier<Map<String, Object>> parameterValuesSupplier;
57  
58    /**
59     * Instantiates a new my batis paging item reader.
60     */
61    public MyBatisPagingItemReader() {
62      setName(getShortName(MyBatisPagingItemReader.class));
63    }
64  
65    /**
66     * Public setter for {@link SqlSessionFactory} for injection purposes.
67     *
68     * @param sqlSessionFactory
69     *          a factory object for the {@link SqlSession}.
70     */
71    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
72      this.sqlSessionFactory = sqlSessionFactory;
73    }
74  
75    /**
76     * Public setter for the statement id identifying the statement in the SqlMap configuration file.
77     *
78     * @param queryId
79     *          the id for the statement
80     */
81    public void setQueryId(String queryId) {
82      this.queryId = queryId;
83    }
84  
85    /**
86     * The parameter values to be used for the query execution.
87     *
88     * @param parameterValues
89     *          the values keyed by the parameter named used in the query string.
90     */
91    public void setParameterValues(Map<String, Object> parameterValues) {
92      this.parameterValues = parameterValues;
93    }
94  
95    /**
96     * The parameter supplier used to get parameter values for the query execution.
97     *
98     * @param parameterValuesSupplier
99     *          the supplier used to get values keyed by the parameter named used in the query string.
100    *
101    * @since 2.1.0
102    */
103   public void setParameterValuesSupplier(Supplier<Map<String, Object>> parameterValuesSupplier) {
104     this.parameterValuesSupplier = parameterValuesSupplier;
105   }
106 
107   /**
108    * Check mandatory properties.
109    *
110    * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
111    */
112   @Override
113   public void afterPropertiesSet() throws Exception {
114     super.afterPropertiesSet();
115     notNull(sqlSessionFactory, "A SqlSessionFactory is required.");
116     notNull(queryId, "A queryId is required.");
117   }
118 
119   @Override
120   protected void doReadPage() {
121     if (sqlSessionTemplate == null) {
122       sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
123     }
124     Map<String, Object> parameters = new HashMap<>();
125     if (parameterValues != null) {
126       parameters.putAll(parameterValues);
127     }
128     Optional.ofNullable(parameterValuesSupplier).map(Supplier::get).ifPresent(parameters::putAll);
129     parameters.put("_page", getPage());
130     parameters.put("_pagesize", getPageSize());
131     parameters.put("_skiprows", getPage() * getPageSize());
132     if (results == null) {
133       results = new CopyOnWriteArrayList<>();
134     } else {
135       results.clear();
136     }
137     results.addAll(sqlSessionTemplate.selectList(queryId, parameters));
138   }
139 
140 }