View Javadoc
1   /*
2    * Copyright 2010-2022 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.Iterator;
23  import java.util.Map;
24  import java.util.Optional;
25  import java.util.function.Supplier;
26  
27  import org.apache.ibatis.cursor.Cursor;
28  import org.apache.ibatis.session.ExecutorType;
29  import org.apache.ibatis.session.SqlSession;
30  import org.apache.ibatis.session.SqlSessionFactory;
31  import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
32  import org.springframework.beans.factory.InitializingBean;
33  
34  /**
35   * @author Guillaume Darmont / guillaume@dropinocean.com
36   */
37  public class MyBatisCursorItemReader<T> extends AbstractItemCountingItemStreamItemReader<T>
38      implements InitializingBean {
39  
40    private String queryId;
41  
42    private SqlSessionFactory sqlSessionFactory;
43    private SqlSession sqlSession;
44  
45    private Map<String, Object> parameterValues;
46    private Supplier<Map<String, Object>> parameterValuesSupplier;
47  
48    private Cursor<T> cursor;
49    private Iterator<T> cursorIterator;
50  
51    public MyBatisCursorItemReader() {
52      setName(getShortName(MyBatisCursorItemReader.class));
53    }
54  
55    @Override
56    protected T doRead() throws Exception {
57      T next = null;
58      if (cursorIterator.hasNext()) {
59        next = cursorIterator.next();
60      }
61      return next;
62    }
63  
64    @Override
65    protected void doOpen() throws Exception {
66      Map<String, Object> parameters = new HashMap<>();
67      if (parameterValues != null) {
68        parameters.putAll(parameterValues);
69      }
70  
71      Optional.ofNullable(parameterValuesSupplier).map(Supplier::get).ifPresent(parameters::putAll);
72  
73      sqlSession = sqlSessionFactory.openSession(ExecutorType.SIMPLE);
74      cursor = sqlSession.selectCursor(queryId, parameters);
75      cursorIterator = cursor.iterator();
76    }
77  
78    @Override
79    protected void doClose() throws Exception {
80      if (cursor != null) {
81        cursor.close();
82      }
83      if (sqlSession != null) {
84        sqlSession.close();
85      }
86      cursorIterator = null;
87    }
88  
89    /**
90     * Check mandatory properties.
91     *
92     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
93     */
94    @Override
95    public void afterPropertiesSet() throws Exception {
96      notNull(sqlSessionFactory, "A SqlSessionFactory is required.");
97      notNull(queryId, "A queryId is required.");
98    }
99  
100   /**
101    * Public setter for {@link SqlSessionFactory} for injection purposes.
102    *
103    * @param sqlSessionFactory
104    *          a factory object for the {@link SqlSession}.
105    */
106   public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
107     this.sqlSessionFactory = sqlSessionFactory;
108   }
109 
110   /**
111    * Public setter for the statement id identifying the statement in the SqlMap configuration file.
112    *
113    * @param queryId
114    *          the id for the statement
115    */
116   public void setQueryId(String queryId) {
117     this.queryId = queryId;
118   }
119 
120   /**
121    * The parameter values to be used for the query execution.
122    *
123    * @param parameterValues
124    *          the values keyed by the parameter named used in the query string.
125    */
126   public void setParameterValues(Map<String, Object> parameterValues) {
127     this.parameterValues = parameterValues;
128   }
129 
130   /**
131    * The parameter supplier used to get parameter values for the query execution.
132    *
133    * @param parameterValuesSupplier
134    *          the supplier used to get values keyed by the parameter named used in the query string.
135    *
136    * @since 2.1.0
137    */
138   public void setParameterValuesSupplier(Supplier<Map<String, Object>> parameterValuesSupplier) {
139     this.parameterValuesSupplier = parameterValuesSupplier;
140   }
141 }