我们先看一下MapperMethod中有哪些select查询,都是如何实现的
case SELECT:
//1.返回void
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
//2.返回集合
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
//3.返回map
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
//4.返回游标
result = executeForCursor(sqlSession, args);
} else {
//5.返回单个对象
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
1.返回void
private void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
//获取MappedStatement
MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
if (!StatementType.CALLABLE.equals(ms.getStatementType())
&& void.class.equals(ms.getResultMaps().get(0).getType())) {
throw new BindingException("method " + command.getName()
+ " needs either a @ResultMap annotation, a @ResultType annotation,"
+ " or a resultType attribute in XML so a ResultHandler can be used as a parameter.");
}
//获取所有的入参
Object param = method.convertArgsToSqlCommandParam(args);
//是否包含分页信息
//调用sqlSession的select方法
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
} else {
sqlSession.select(command.getName(), param, method.extractResultHandler(args));
}
}
我们看下sqlsession的select方法:
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
//获取MappedStatement
MappedStatement ms = configuration.getMappedStatement(statement);
//执行executor的query方法
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
这里其实是调用了BaseExecuto的query方法:
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//获取执行的sql信息
BoundSql boundSql = ms.getBoundSql(parameter);
//获取当前执行方法的缓存key
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
//执行方法
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
//判断是否从走缓存
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//不走缓存 执行查询
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}
我们先看一下取缓存数据后的对参数的操作:
private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) {
if (ms.getStatementType() == StatementType.CALLABLE) {
final Object cachedParameter = localOutputParameterCache.getObject(key);
if (cachedParameter != null && parameter != null) {
final MetaObject metaCachedParameter = configuration.newMetaObject(cachedParameter);
final MetaObject metaParameter = configuration.newMetaObject(parameter);
for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
if (parameterMapping.getMode() != ParameterMode.IN) {
final String parameterName = parameterMapping.getProperty();
final Object cachedValue = metaCachedParameter.getValue(parameterName);
metaParameter.setValue(parameterName, cachedValue);
}
}
}
}
}
然后是不走缓存,查询数据库的操作:
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
//执行查询操作
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
//把当前查询结果放到缓存中
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
这里doquery其实是SimpleExecutor的方法:
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
//1.获取配置信息
Configuration configuration = ms.getConfiguration();
//2.获取StatementHandler 并初始化数据
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//3.获取Statement 对象
stmt = prepareStatement(handler, ms.getStatementLog());
//4.执行StatementHandler 的query方法
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
我们可以看到这里的1,2,3步跟前面的insert,update,delete的操作是一致的,不做解析,我们主要看第4步的查询方法:
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
//执行PreparedStatement 的execute方法
ps.execute();
//解析返回的数据
return resultSetHandler.<E> handleResultSets(ps);
}
这里我们主要看返回数据的解析,这里调用的是resultSetHandler对象的handleResultSets的方法:这里的resultSetHandler也是在获取statementHandler的时候初始化的:调用的是configuration的方法
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
//初始化一个DefaultResultSetHandler
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
//在DefaultResultSetHandler上添加插件拦截器链
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
下面我们看一下具体解析返回的参数方法:
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<Object>();
int resultSetCount = 0;
//获取第一条数据
ResultSetWrapper rsw = getFirstResultSet(stmt);
//获取当前方法的ResultMap数据
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
//获取ResultMap个数,一般都是一个
int resultMapCount = resultMaps.size();
//校验查询数据是否有效
validateResultMapsCount(rsw, resultMapCount);
//循环解析每一个ResultSet 也就是必须设定了返回的ResultMap
//如果设定不是ResultMap 走后面的resultSets逻辑
while (rsw != null && resultMapCount > resultSetCount) {
//获取当前对应的ResultMap 数据 也就是返回字段的定义
ResultMap resultMap = resultMaps.get(resultSetCount);
//解析转换赋值
handleResultSet(rsw, resultMap, multipleResults, null);
//获取下一个ResultSet进行后续解析
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
//这里判断是不是设置的resultType
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
//循环解析每个resultSet
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
//获取下一个resultSet
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
//返回解析后的数据
return collapseSingleResultList(multipleResults);
}
我们看一下每一个ResultSet数据的解析:
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
try {
if (parentMapping != null) {
//解析ResultSet数据
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else {
if (resultHandler == null) {
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
//解析ResultSet数据
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
//只有这种情况返回的是我们自定义的list 一般都是走的这里
//把上一步的defaultResultHandler的list添加到multipleResults中
multipleResults.add(defaultResultHandler.getResultList());
} else {
//解析ResultSet数据
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// issue #228 (close resultsets)
closeResultSet(rsw.getResultSet());
}
}
//解析ResultSet数据
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
//ResultMap有子集关系的
if (resultMap.hasNestedResultMaps()) {
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
//普通单一ResultMap
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
//普通单一ResultMap
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
//如果有分页参数 跳过前面的数据
skipRows(rsw.getResultSet(), rowBounds);
//循环解析每行数据
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
//获取行数据
Object rowValue = getRowValue(rsw, discriminatedResultMap);
//这里把行数据设置到resultContext里面
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
//这里把行数据设置到resultContext里面
private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
if (parentMapping != null) {
linkToParents(rs, parentMapping, rowValue);
} else {
//rowValue设置到resultContext
callResultHandler(resultHandler, resultContext, rowValue);
}
}
//rowValue设置到resultContext
private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
//把rowValue设置给resultContext的resultObject
resultContext.nextResultObject(rowValue);
把当前resultContext的resultObject设置到DefaultResultHandler的list中
((ResultHandler<Object>) resultHandler).handleResult(resultContext);
}
2.返回集合
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
List<E> result;
//获取入参
Object param = method.convertArgsToSqlCommandParam(args);
//有没有分页信息
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
//调用sqlSession.selectList方法 最终都是走的query方法,跟返回void一致不在说明
result = sqlSession.<E>selectList(command.getName(), param, rowBounds);
} else {
//调用sqlSession.selectList方法,跟返回void一致不在说明
result = sqlSession.<E>selectList(command.getName(), param);
}
// issue #510 Collections & arrays support
if (!method.getReturnType().isAssignableFrom(result.getClass())) {
//返回数据是数组
if (method.getReturnType().isArray()) {
return convertToArray(result);
} else {
//集合
return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
}
}
return result;
}
//返回数据是数组
private <E> Object convertToArray(List<E> list) {
Class<?> arrayComponentType = method.getReturnType().getComponentType();
Object array = Array.newInstance(arrayComponentType, list.size());
if (arrayComponentType.isPrimitive()) {
for (int i = 0; i < list.size(); i++) {
Array.set(array, i, list.get(i));
}
return array;
} else {
return list.toArray((E[])array);
}
}
//集合
private <E> Object convertToDeclaredCollection(Configuration config, List<E> list) {
Object collection = config.getObjectFactory().create(method.getReturnType());
MetaObject metaObject = config.newMetaObject(collection);
metaObject.addAll(list);
return collection;
}
3.返回map
private <K, V> Map<K, V> executeForMap(SqlSession sqlSession, Object[] args) {
Map<K, V> result;
//获取入参
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
//调用sqlSession.selectMap方法
result = sqlSession.<K, V>selectMap(command.getName(), param, method.getMapKey(), rowBounds);
} else {
result = sqlSession.<K, V>selectMap(command.getName(), param, method.getMapKey());
}
return result;
}
//调用sqlSession.selectMap方法
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
//这里调用的是selectList方法 上面已经解析过 不在解析
final List<? extends V> list = selectList(statement, parameter, rowBounds);
//这里把数据转换成map格式
final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<K, V>(mapKey,
configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());
final DefaultResultContext<V> context = new DefaultResultContext<V>();
for (V o : list) {
context.nextResultObject(o);
mapResultHandler.handleResult(context);
}
return mapResultHandler.getMappedResults();
}
4.返回Cursor
private <T> Cursor<T> executeForCursor(SqlSession sqlSession, Object[] args) {
Cursor<T> result;
//获取入参
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
//调用sqlSession.selectCursor方法
result = sqlSession.<T>selectCursor(command.getName(), param, rowBounds);
} else {
//调用sqlSession.selectCursor方法
result = sqlSession.<T>selectCursor(command.getName(), param);
}
return result;
}
//调用sqlSession.selectCursor方法
public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
try {
//获取MappedStatement
MappedStatement ms = configuration.getMappedStatement(statement);
//调用executor.queryCursor方法
Cursor<T> cursor = executor.queryCursor(ms, wrapCollection(parameter), rowBounds);
//把当前cursor添加到cursorList中
registerCursor(cursor);
return cursor;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//调用executor.queryCursor方法
public <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {
//获取执行SQL信息
BoundSql boundSql = ms.getBoundSql(parameter);
//调用simpleexecutor.doQueryCursor方法
return doQueryCursor(ms, parameter, rowBounds, boundSql);
}
//调用simpleexecutor.doQueryCursor方法
protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
Statement stmt = prepareStatement(handler, ms.getStatementLog());
//这里把获取的数据转换成Cursor
return handler.<E>queryCursor(stmt);
}
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.<E> handleCursorResultSets(ps);
}
//这里跟前面的解析基本一致 主要是把ResultMap 转换成DefaultCursor
public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling cursor results").object(mappedStatement.getId());
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
if (resultMapCount != 1) {
throw new ExecutorException("Cursor results cannot be mapped to multiple resultMaps");
}
ResultMap resultMap = resultMaps.get(0);
return new DefaultCursor<E>(this, resultMap, rsw, rowBounds);
}
//把ResultMap 转换成DefaultCursor
public DefaultCursor(DefaultResultSetHandler resultSetHandler, ResultMap resultMap, ResultSetWrapper rsw, RowBounds rowBounds) {
this.resultSetHandler = resultSetHandler;
this.resultMap = resultMap;
this.rsw = rsw;
this.rowBounds = rowBounds;
}
5.返回单一对象:这里直接调用的sqlsession.selectOne方法:主要是调用selectList方法
public <T> T selectOne(String statement, Object parameter) {
// 调用selectList方法
List<T> list = this.<T>selectList(statement, parameter);
//这里判断 必须只能返回一条数据 如果多于1条 抛出异常
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}