mybatis源码解析4---SqlSession解析
Posted Lucky帅小武
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis源码解析4---SqlSession解析相关的知识,希望对你有一定的参考价值。
由之前解析可知,mybatis启动的时候会加载XML配置文件解析生成全局配置对象Configuration对象,SqlSessionFactoryBuilder类会根据Configuration对象创建一个DefaultSqlSessionFactory对象,而DefaultSqlSessionFactory对象实现了SqlSessionFactory中的创建SqlSession的方法,最终新建了一个SqlSession接口的默认实现类DefaultSqlSession,现在先来了解下SqlSession以及它的实现类
SqlSession解析
SqlSession位于mybatis包的org.apache.ibatis.session目录下,字面意思就是sql的会话,用于程序和数据库直接的sql会话,程序执行一次数据库操作就需要创建一个sqlSession,操作结束即关闭sqlSession;
既然是程序和数据库之间的会话,那么sqlSession接口的方法应该是程序和数据库都容易理解的,sqlSession中定义的方法都是关于数据库操作的方法,源码如下:
1 package org.apache.ibatis.session; 2 3 import java.io.Closeable; 4 import java.sql.Connection; 5 import java.util.List; 6 import java.util.Map; 7 8 import org.apache.ibatis.cursor.Cursor; 9 import org.apache.ibatis.executor.BatchResult; 10 11 public interface SqlSession extends Closeable { 12 13 //根据Sql语句查询单条记录 14 <T> T selectOne(String statement); 15 <T> T selectOne(String statement, Object parameter);//根据Sql语句和参数查询单条记录 16 17 //根据Sql语句查询多条记录 18 <E> List<E> selectList(String statement); 19 <E> List<E> selectList(String statement, Object parameter);//根据Sql语句和参数查询多条记录 20 <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);//根据Sql语句和参数以及分页参数查询多条记录 21 22 //selectMap和selectList原理一样,只是将结果集映射成Map对象返回 23 <K, V> Map<K, V> selectMap(String statement, String mapKey); 24 <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey); 25 <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds); 26 27 //返回游标对象 28 <T> Cursor<T> selectCursor(String statement); 29 <T> Cursor<T> selectCursor(String statement, Object parameter); 30 <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds); 31 32 //查询的结果对象由指定的ResultHandler处理 33 void select(String statement, Object parameter, ResultHandler handler); 34 void select(String statement, ResultHandler handler); 35 void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler); 36 37 //执行insert语句 38 int insert(String statement); 39 int insert(String statement, Object parameter); 40 41 //执行update语句 42 int update(String statement); 43 int update(String statement, Object parameter); 44 45 //执行delete语句 46 int delete(String statement); 47 int delete(String statement, Object parameter); 48 49 //提交事务 50 void commit(); 51 void commit(boolean force); 52 53 //事务回滚 54 void rollback(); 55 void rollback(boolean force); 56 57 //将请求刷新到数据库 58 List<BatchResult> flushStatements(); 59 60 //关闭sqlSession 61 @Override 62 void close(); 63 64 //清除缓存 65 void clearCache(); 66 67 //获取Configuration对象 68 Configuration getConfiguration(); 69 70 //获取Type对象的Mapper对象 71 <T> T getMapper(Class<T> type); 72 73 //获取sqlSession对象的数据库连接 74 Connection getConnection(); 75 }
SqlSession中的方法全是和数据库相关的增删改查以及事务的提交方法。
SqlSession有三个实现类,除了默认的DefaultSqlSession之外,还有SqlSessionManager和SqlSessionTemplate
接下来先看下SqlSession默认的实现类DefaultSqlSession是如何实现的。
DefaultSqlSession类解析
DefaultSqlSession有5个属性和2个构造方法如下:
1 private Configuration configuration;//全局配置 2 private Executor executor;//执行器 3 4 private boolean autoCommit;//自动提交标识 5 private boolean dirty; 6 private List<Cursor<?>> cursorList;//游标列表 7 8 public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) { 9 this.configuration = configuration; 10 this.executor = executor; 11 this.dirty = false; 12 this.autoCommit = autoCommit; 13 } 14 15 public DefaultSqlSession(Configuration configuration, Executor executor) { 16 this(configuration, executor, false); 17 }
下面以select方法为例
1 @Override 2 public <T> T selectOne(String statement) { 3 return this.<T>selectOne(statement, null); 4 } 5 6 @Override 7 public <T> T selectOne(String statement, Object parameter) { 8 // Popular vote was to return null on 0 results and throw exception on too many. 9 List<T> list = this.<T>selectList(statement, parameter); 10 if (list.size() == 1) { 11 return list.get(0); 12 } else if (list.size() > 1) { 13 throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); 14 } else { 15 return null; 16 } 17 }
很明显selectOne的方法最终都是调用了selectList方法,然后取唯一的一条数据返回。那在看看selectList相关的代码
1 @Override 2 public <E> List<E> selectList(String statement) { 3 return this.selectList(statement, null); 4 } 5 6 @Override 7 public <E> List<E> selectList(String statement, Object parameter) { 8 return this.selectList(statement, parameter, RowBounds.DEFAULT); 9 } 10 11 @Override 12 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { 13 try { 14 MappedStatement ms = configuration.getMappedStatement(statement); 15 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); 16 } catch (Exception e) { 17 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); 18 } finally { 19 ErrorContext.instance().reset(); 20 } 21 }
共有三个selectList方法,最终都是调用了最后一个selectList方法,这里有三个参数:statement是sql语句;parameter是传入的参数;RowBounds是和分页相关的参数
RowBounds源码如下:
1 package org.apache.ibatis.session; 2 3 /** 4 * @author Clinton Begin 5 */ 6 public class RowBounds { 7 8 public static final int NO_ROW_OFFSET = 0; 9 public static final int NO_ROW_LIMIT = Integer.MAX_VALUE; //int的最大值 10 public static final RowBounds DEFAULT = new RowBounds(); 11 12 private int offset; 13 private int limit; 14 15 public RowBounds() { 16 this.offset = NO_ROW_OFFSET; 17 this.limit = NO_ROW_LIMIT; 18 } 19 20 public RowBounds(int offset, int limit) { 21 this.offset = offset; 22 this.limit = limit; 23 } 24 25 public int getOffset() { 26 return offset; 27 } 28 29 public int getLimit() { 30 return limit; 31 } 32 33 }
RowBounds的两个属性:offSet是指查询数据时从多少位置开始查询,limit是指返回数据的调试,默认是从0位置开始查询到Integer的最大值,相关于默认是不做分页处理;
回到正题,selectList最后执行的方法中执行了两行代码
1 MappedStatement ms = configuration.getMappedStatement(statement); 2 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
调用configuration的getMapped的Statement方法获取MappedStatement对象,然后调用执行器executor的query方法获取查询结果。
这是select方法,再来看看其他的insert、update、delete方法
1 @Override 2 public int insert(String statement) { 3 return insert(statement, null); 4 } 5 6 @Override 7 public int insert(String statement, Object parameter) { 8 return update(statement, parameter); 9 } 10 11 @Override 12 public int update(String statement) { 13 return update(statement, null); 14 } 15 16 @Override 17 public int update(String statement, Object parameter) { 18 try { 19 dirty = true; 20 MappedStatement ms = configuration.getMappedStatement(statement); 21 return executor.update(ms, wrapCollection(parameter)); 22 } catch (Exception e) { 23 throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); 24 } finally { 25 ErrorContext.instance().reset(); 26 } 27 } 28 29 @Override 30 public int delete(String statement) { 31 return update(statement, null); 32 } 33 34 @Override 35 public int delete(String statement, Object parameter) { 36 return update(statement, parameter); 37 }
可以看出SqlSession的insert和delete的方法最终都是调用了update方法,而update方法最终也是调用了Executor的update
由此可得出结论sqlSession虽然叫程序和数据库之间的SQL会话,但是它并没有具体去执行sql语句,最终的sql语句的执行是由执行器Executor执行的,而SqlSession的作用只是创建了MappedStatement对象以及调用执行器去执行SQL
其他的commit、rollback方法同样最终都是调用的执行器Executor的对应的方法,那么接下来就去了解下执行器Executor是干嘛的,以及SqlSession创建的MappedStatement又是什么?
DefaultSqlSession完整源码如下:
1 /** 2 * Copyright 2009-2015 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 * http://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.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 * The default implementation for {@link SqlSession}. 45 * Note that this class is not Thread-Safe. 46 * 47 * @author Clinton Begin 48 */ 49 public class DefaultSqlSession implements SqlSession { 50 51 private Configuration configuration; 52 private Executor executor; 53 54 private boolean autoCommit; 55 private boolean dirty; 56 private List<Cursor<?>> cursorList; 57 58 public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) { 59 this.configuration = configuration; 60 this.executor = executor; 61 this.dirty = false; 62 this.autoCommit = autoCommit; 63 } 64 65 public DefaultSqlSession(Configuration configuration, Executor executor) { 66 this(configuration, executor, false); 67 } 68 69 @Override 70 public <T> T selectOne(String statement) { 71 return this.<T>selectOne(statement, null); 72 } 73 74 @Override 75 public <T> T selectOne(String statement, Object parameter) { 76 // Popular vote was to return null on 0 results and throw exception on too many. 77 List<T> list = this.<T>selectList(statement, parameter); 78 if (list.size() == 1) { 79 return list.get(0); 80 } else if (list.size() > 1) { 81 throw new TooManyResultsException("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<K, V>(mapKey, 101 configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory()); 102 final DefaultResultContext<V> context = new DefaultResultContext<V>(); 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 Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds); 125 registerCursor(cursor); 126 return cursor; 127 } catch (Exception e) { 128 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); 129 } finally { 130 ErrorContext.instance().reset(); 131 } 132 } 133 134 @Override 135 public <E> List<E> selectList(String statement) { 136 return this.selectList(statement, null); 137 } 138 139 @Override 140 public <E> List<E> selectList(String statement, Object parameter) { 141 return this.selectList(statement, parameter, RowBounds.DEFAULT); 142 } 143 144 @Override 145 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { 146 try { 147 MappedStatement ms = configuration.getMappedStatement(statement); 148 return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); 149 } catch (Exception e) { 150 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); 151 } finally { 152 ErrorContext.instance().reset(); 153 } 154 } 155 156 @Override 157 public void select(String statement, Object parameter, ResultHandler handler) { 158 select(statement, parameter, RowBounds.DEFAULT, handler); 159 } 160 161 @Override 162 public void select(String statement, ResultHandler handler) { 163 select(statement, null, RowBounds.DEFAULT, handler); 164 } 165 166 @Override 167 public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { 168 try { 169 MappedStatement ms = configuration.getMappedStatement(statement); 170 executor.query(ms, wrapCollection(parameter), rowBounds, handler); 171 } catch (Exception e) { 172 throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); 173 } finally { 174 ErrorContext.instance().reset(); 175 } 176 } 177 178 @Override 179 public int insert(String statement) { 180 return insert(statement, null); 181 } 182 183 @Override 184 public int insert(String statement, Object parameter) { 185 return update(statement, parameter); 186 } 187 188 @Override 189 public int update(String statement) { 190 return update(statement, null); 191 } 192 193 @Override 194 public int update(String statement, Object parameter) { 195 try { 196 dirty = true; 197 MappedStatement ms = configuration.getMappedStatement(statement); 198 return executor.update(ms, wrapCollection(parameter)); 199 } catch (Exception e) { 200 throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); 201 } finally { 202 ErrorContext.instance().reset(); 203 } 204 } 205 206 @Override 207 public int delete(String statement) { 208 return update(statement, null); 209 } 210 211 @Override 212 public int delete(String statement, Object parameter) { 213 return update(statement, parameter); 214 } 215 216 @Override 217 public void commit() { 218 commit(false); 219 } 220 221 @Override 222 public void commit(boolean force) { 223 try { 224 executor.commit(isCommitOrRollbackRequired(force)); 225 dirty = false; 226 } catch (Exception e) { 227 throw ExceptionFactory.wrapException("Error committing transaction. Cause: " + e, e); 228 } finally { 229 ErrorContext.instance().reset(); 230 } 231 } 232 233 @Override 234 public void rollback() { 235 rollback(false); 236 } 237 238 @Override 239 public void rollback(boolean force) { 240 try { 241 executor.rollback(isCommitOrRollbackRequired(force)); 242 dirty = false; 243 } catch (Exception e) { 244 throw ExceptionFactory.wrapException("Error rolling back transaction. Cause: " + e, e); 245 } finally { 246 ErrorContext.instance().reset(); 247 } 248 } 249 250 @Override 251 public List<BatchResult> flushStatements() { 252 try { 253 return executor.flushStatements(); 254 } catch (Exception e) { 255 throw ExceptionFactory.wrapException("Error flushing statements. Cause: " + e, e); 256 } finally { 257 ErrorContext.instance().reset(); 258 } 259 } 260 261 @Override 262 public void close() { 263 try { 264 executor.close(isCommitOrRollbackRequired(false)); 265 closeCursors(); 266 dirty = false; 267 } finally { 268 ErrorContext.instance().reset(); 269 } 270 } 271 272 private void closeCursors() { 273 if (cursorList != null && cursorList.size() != 0) { 274 for (Cursor<?> cursor : cursorList) { 275 try { 276 cursor.close(); 277 } catch (IOException e) { 278 throw ExceptionFactory.wrapException("Error closing cursor. Cause: " + e, e); 279 } 280 } 281 cursorList.clear(); 282 } 283 } 284 285 @Override 286 public Configuration getConfiguration() { 287 return configuration; 288 } 289 290 @Override 291 public <T> T getMapper(Class<T> type) { 292 return configuration.<T>getMapper(type, this); 293 } 294 295 @Override 296 public Connection getConnection() { 297 try { 298 return executor.getTransaction().getConnection(); 299 } catch (SQLException e) { 300 throw ExceptionFactory.wrapException("Error getting a new connection. Cause: " + e, e); 301 } 302 } 303 304 @Override 305 public void clearCache() { 306 executor.clearLocalCache(); 307 } 308 309 private <T> void registerCursor(Cursor<T> cursor) { 310 if (cursorList == null) { 311 cursorList = new ArrayList<Cursor<?>>(); 312 } 313 cursorList.add(cursor); 314 } 315 316 private boolean isCommitOrRollbackRequired(boolean force) { 317 return (!autoCommit && dirty) || force; 318 } 319 320 private Object wrapCollection(final Object object) { 321 if (object instanceof Collection) { 322 StrictMap<Object> map = new StrictMap<Object>(); 323 map.put("collection", object); 324 if (object instanceof List) { 325 map.put("list", object); 326 } 327 return map; 328 } else if (object != null && object.getClass().isArray()) { 329 StrictMap<Object> map = new StrictMap<Object>(); 330 map.put("array", object); 331 return map; 332 } 333 return object; 334 } 335 336 public static class StrictMap<V> extends HashMap<String, V> { 337 338 private static final long serialVersionUID = -5741767162221585340L; 339 340 @Override 341 public V get(Object key) { 342 if (!super.containsKey(key)) { 343 throw new BindingException("Parameter ‘" + key + "‘ not found. Available parameters are " + this.keySet()); 344 } 345 return super.get(key); 346 } 347 348 } 349 350 }
以上是关于mybatis源码解析4---SqlSession解析的主要内容,如果未能解决你的问题,请参考以下文章