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.HashMap;
23 import java.util.List;
24 import java.util.Map;
25
26 import org.apache.ibatis.binding.BindingException;
27 import org.apache.ibatis.cursor.Cursor;
28 import org.apache.ibatis.exceptions.ExceptionFactory;
29 import org.apache.ibatis.exceptions.TooManyResultsException;
30 import org.apache.ibatis.executor.BatchResult;
31 import org.apache.ibatis.executor.ErrorContext;
32 import org.apache.ibatis.executor.Executor;
33 import org.apache.ibatis.executor.result.DefaultMapResultHandler;
34 import org.apache.ibatis.executor.result.DefaultResultContext;
35 import org.apache.ibatis.mapping.MappedStatement;
36 import org.apache.ibatis.reflection.ParamNameResolver;
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 public class DefaultSqlSession implements SqlSession {
48
49 private final Configuration configuration;
50 private final Executor executor;
51
52 private final boolean autoCommit;
53 private boolean dirty;
54 private List<Cursor<?>> cursorList;
55
56 public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
57 this.configuration = configuration;
58 this.executor = executor;
59 this.dirty = false;
60 this.autoCommit = autoCommit;
61 }
62
63 public DefaultSqlSession(Configuration configuration, Executor executor) {
64 this(configuration, executor, false);
65 }
66
67 @Override
68 public <T> T selectOne(String statement) {
69 return this.selectOne(statement, null);
70 }
71
72 @Override
73 public <T> T selectOne(String statement, Object parameter) {
74
75 List<T> list = this.selectList(statement, parameter);
76 if (list.size() == 1) {
77 return list.get(0);
78 }
79 if (list.size() > 1) {
80 throw new TooManyResultsException(
81 "Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
82 } else {
83 return null;
84 }
85 }
86
87 @Override
88 public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
89 return this.selectMap(statement, null, mapKey, RowBounds.DEFAULT);
90 }
91
92 @Override
93 public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
94 return this.selectMap(statement, parameter, mapKey, RowBounds.DEFAULT);
95 }
96
97 @Override
98 public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
99 final List<? extends V> list = selectList(statement, parameter, rowBounds);
100 final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,
101 configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
102 final DefaultResultContext<V> context = new DefaultResultContext<>();
103 for (V o : list) {
104 context.nextResultObject(o);
105 mapResultHandler.handleResult(context);
106 }
107 return mapResultHandler.getMappedResults();
108 }
109
110 @Override
111 public <T> Cursor<T> selectCursor(String statement) {
112 return selectCursor(statement, null);
113 }
114
115 @Override
116 public <T> Cursor<T> selectCursor(String statement, Object parameter) {
117 return selectCursor(statement, parameter, RowBounds.DEFAULT);
118 }
119
120 @Override
121 public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
122 try {
123 MappedStatement ms = configuration.getMappedStatement(statement);
124 dirty |= ms.isDirtySelect();
125 Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
126 registerCursor(cursor);
127 return cursor;
128 } catch (Exception e) {
129 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
130 } finally {
131 ErrorContext.instance().reset();
132 }
133 }
134
135 @Override
136 public <E> List<E> selectList(String statement) {
137 return this.selectList(statement, null);
138 }
139
140 @Override
141 public <E> List<E> selectList(String statement, Object parameter) {
142 return this.selectList(statement, parameter, RowBounds.DEFAULT);
143 }
144
145 @Override
146 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
147 return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
148 }
149
150 private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
151 try {
152 MappedStatement ms = configuration.getMappedStatement(statement);
153 dirty |= ms.isDirtySelect();
154 return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
155 } catch (Exception e) {
156 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
157 } finally {
158 ErrorContext.instance().reset();
159 }
160 }
161
162 @Override
163 public void select(String statement, Object parameter, ResultHandler handler) {
164 select(statement, parameter, RowBounds.DEFAULT, handler);
165 }
166
167 @Override
168 public void select(String statement, ResultHandler handler) {
169 select(statement, null, RowBounds.DEFAULT, handler);
170 }
171
172 @Override
173 public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
174 selectList(statement, parameter, rowBounds, handler);
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 return ParamNameResolver.wrapToMapIfCollection(object, null);
321 }
322
323
324
325
326 @Deprecated
327 public static class StrictMap<V> extends HashMap<String, V> {
328
329 private static final long serialVersionUID = -5741767162221585340L;
330
331 @Override
332 public V get(Object key) {
333 if (!super.containsKey(key)) {
334 throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + this.keySet());
335 }
336 return super.get(key);
337 }
338
339 }
340
341 }