1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.session.defaults;
17
18 import java.io.IOException;
19 import java.sql.Connection;
20 import java.sql.SQLException;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26
27 import org.apache.ibatis.binding.BindingException;
28 import org.apache.ibatis.cursor.Cursor;
29 import org.apache.ibatis.exceptions.ExceptionFactory;
30 import org.apache.ibatis.exceptions.TooManyResultsException;
31 import org.apache.ibatis.executor.BatchResult;
32 import org.apache.ibatis.executor.ErrorContext;
33 import org.apache.ibatis.executor.Executor;
34 import org.apache.ibatis.executor.result.DefaultMapResultHandler;
35 import org.apache.ibatis.executor.result.DefaultResultContext;
36 import org.apache.ibatis.mapping.MappedStatement;
37 import org.apache.ibatis.session.Configuration;
38 import org.apache.ibatis.session.ResultHandler;
39 import org.apache.ibatis.session.RowBounds;
40 import org.apache.ibatis.session.SqlSession;
41
42
43
44
45
46
47
48 public class DefaultSqlSession implements SqlSession {
49
50 private final Configuration configuration;
51 private final Executor executor;
52
53 private final boolean autoCommit;
54 private boolean dirty;
55 private List<Cursor<?>> cursorList;
56
57 public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
58 this.configuration = configuration;
59 this.executor = executor;
60 this.dirty = false;
61 this.autoCommit = autoCommit;
62 }
63
64 public DefaultSqlSession(Configuration configuration, Executor executor) {
65 this(configuration, executor, false);
66 }
67
68 @Override
69 public <T> T selectOne(String statement) {
70 return this.selectOne(statement, null);
71 }
72
73 @Override
74 public <T> T selectOne(String statement, Object parameter) {
75
76 List<T> list = this.selectList(statement, parameter);
77 if (list.size() == 1) {
78 return list.get(0);
79 } else if (list.size() > 1) {
80 throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
81 } else {
82 return null;
83 }
84 }
85
86 @Override
87 public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
88 return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
89 }
90
91 @Override
92 public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
93 return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
94 }
95
96 @Override
97 public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
98 final List<? extends V> list = selectList(statement, parameter, rowBounds);
99 final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,
100 configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
101 final DefaultResultContext<V> context = new DefaultResultContext<>();
102 for (V o : list) {
103 context.nextResultObject(o);
104 mapResultHandler.handleResult(context);
105 }
106 return mapResultHandler.getMappedResults();
107 }
108
109 @Override
110 public <T> Cursor<T> selectCursor(String statement) {
111 return selectCursor(statement, null);
112 }
113
114 @Override
115 public <T> Cursor<T> selectCursor(String statement, Object parameter) {
116 return selectCursor(statement, parameter, RowBounds.DEFAULT);
117 }
118
119 @Override
120 public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
121 try {
122 MappedStatement ms = configuration.getMappedStatement(statement);
123 Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
124 registerCursor(cursor);
125 return cursor;
126 } catch (Exception e) {
127 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
128 } finally {
129 ErrorContext.instance().reset();
130 }
131 }
132
133 @Override
134 public <E> List<E> selectList(String statement) {
135 return this.selectList(statement, null);
136 }
137
138 @Override
139 public <E> List<E> selectList(String statement, Object parameter) {
140 return this.selectList(statement, parameter, RowBounds.DEFAULT);
141 }
142
143 @Override
144 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
145 try {
146 MappedStatement ms = configuration.getMappedStatement(statement);
147 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
148 } catch (Exception e) {
149 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
150 } finally {
151 ErrorContext.instance().reset();
152 }
153 }
154
155 @Override
156 public void select(String statement, Object parameter, ResultHandler handler) {
157 select(statement, parameter, RowBounds.DEFAULT, handler);
158 }
159
160 @Override
161 public void select(String statement, ResultHandler handler) {
162 select(statement, null, RowBounds.DEFAULT, handler);
163 }
164
165 @Override
166 public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
167 try {
168 MappedStatement ms = configuration.getMappedStatement(statement);
169 executor.query(ms, wrapCollection(parameter), rowBounds, handler);
170 } catch (Exception e) {
171 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
172 } finally {
173 ErrorContext.instance().reset();
174 }
175 }
176
177 @Override
178 public int insert(String statement) {
179 return insert(statement, null);
180 }
181
182 @Override
183 public int insert(String statement, Object parameter) {
184 return update(statement, parameter);
185 }
186
187 @Override
188 public int update(String statement) {
189 return update(statement, null);
190 }
191
192 @Override
193 public int update(String statement, Object parameter) {
194 try {
195 dirty = true;
196 MappedStatement ms = configuration.getMappedStatement(statement);
197 return executor.update(ms, wrapCollection(parameter));
198 } catch (Exception e) {
199 throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
200 } finally {
201 ErrorContext.instance().reset();
202 }
203 }
204
205 @Override
206 public int delete(String statement) {
207 return update(statement, null);
208 }
209
210 @Override
211 public int delete(String statement, Object parameter) {
212 return update(statement, parameter);
213 }
214
215 @Override
216 public void commit() {
217 commit(false);
218 }
219
220 @Override
221 public void commit(boolean force) {
222 try {
223 executor.commit(isCommitOrRollbackRequired(force));
224 dirty = false;
225 } catch (Exception e) {
226 throw ExceptionFactory.wrapException("Error committing transaction. Cause: " + e, e);
227 } finally {
228 ErrorContext.instance().reset();
229 }
230 }
231
232 @Override
233 public void rollback() {
234 rollback(false);
235 }
236
237 @Override
238 public void rollback(boolean force) {
239 try {
240 executor.rollback(isCommitOrRollbackRequired(force));
241 dirty = false;
242 } catch (Exception e) {
243 throw ExceptionFactory.wrapException("Error rolling back transaction. Cause: " + e, e);
244 } finally {
245 ErrorContext.instance().reset();
246 }
247 }
248
249 @Override
250 public List<BatchResult> flushStatements() {
251 try {
252 return executor.flushStatements();
253 } catch (Exception e) {
254 throw ExceptionFactory.wrapException("Error flushing statements. Cause: " + e, e);
255 } finally {
256 ErrorContext.instance().reset();
257 }
258 }
259
260 @Override
261 public void close() {
262 try {
263 executor.close(isCommitOrRollbackRequired(false));
264 closeCursors();
265 dirty = false;
266 } finally {
267 ErrorContext.instance().reset();
268 }
269 }
270
271 private void closeCursors() {
272 if (cursorList != null && !cursorList.isEmpty()) {
273 for (Cursor<?> cursor : cursorList) {
274 try {
275 cursor.close();
276 } catch (IOException e) {
277 throw ExceptionFactory.wrapException("Error closing cursor. Cause: " + e, e);
278 }
279 }
280 cursorList.clear();
281 }
282 }
283
284 @Override
285 public Configuration getConfiguration() {
286 return configuration;
287 }
288
289 @Override
290 public <T> T getMapper(Class<T> type) {
291 return configuration.getMapper(type, this);
292 }
293
294 @Override
295 public Connection getConnection() {
296 try {
297 return executor.getTransaction().getConnection();
298 } catch (SQLException e) {
299 throw ExceptionFactory.wrapException("Error getting a new connection. Cause: " + e, e);
300 }
301 }
302
303 @Override
304 public void clearCache() {
305 executor.clearLocalCache();
306 }
307
308 private <T> void registerCursor(Cursor<T> cursor) {
309 if (cursorList == null) {
310 cursorList = new ArrayList<>();
311 }
312 cursorList.add(cursor);
313 }
314
315 private boolean isCommitOrRollbackRequired(boolean force) {
316 return (!autoCommit && dirty) || force;
317 }
318
319 private Object wrapCollection(final Object object) {
320 if (object instanceof Collection) {
321 StrictMap<Object> map = new StrictMap<>();
322 map.put("collection", object);
323 if (object instanceof List) {
324 map.put("list", object);
325 }
326 return map;
327 } else if (object != null && object.getClass().isArray()) {
328 StrictMap<Object> map = new StrictMap<>();
329 map.put("array", object);
330 return map;
331 }
332 return object;
333 }
334
335 public static class StrictMap<V> extends HashMap<String, V> {
336
337 private static final long serialVersionUID = -5741767162221585340L;
338
339 @Override
340 public V get(Object key) {
341 if (!super.containsKey(key)) {
342 throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + this.keySet());
343 }
344 return super.get(key);
345 }
346
347 }
348
349 }