之所以要说这个,是因为其他方法都跟这个差不多,而且这个才涉及到参数的填充过程等,这个过程你看懂了,其他的方法就难不倒你了,先看下基本的代码编写
样例
//工厂工具类
public class FactoryUtils {
public static SqlSessionFactory sqlSessionFactory() {
return sqlSessionFactory(null);
}
public static SqlSessionFactory sqlSessionFactory(Properties properties) {
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
return new SqlSessionFactoryBuilder().build(inputStream, properties);
}
}
//sql执行测试类
public class SqlSessionTest {
public static void main(String[] args) throws Exception{
//获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = FactoryUtils.sqlSessionFactory();
//打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//执行sql语句
List<User> userList = sqlSession.selectList("com.zxc.study.test.mapper.UserMapper.selectUser", 1);
//操作返回结构
System.out.println(userList);
}
}
源码入口之sqlSession.selectList
org.apache.ibatis.session.defaults.DefaultSqlSession#selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)
RowBounds 默认为 RowBounds.DEFAUL
ResultHandler 默认为 NULL
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//从配置中获取MappedStatement对象,其实就是一个map,key就是statement组装的
MappedStatement ms = configuration.getMappedStatement(statement);
//使用executor对象执行查询逻辑
//wrapCollection包装参数,有可能传进来的是集合
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
第一步就是从一个map中获取 MappedStatement 对象,没什么好看的
第二步才是核心的操作过程
至于 wrapCollection只是判断了一下参数是Collection或者是Array进行了一层包装
Executor(CachingExecutor).query
首先会先到 org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)中
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//获取绑定sql对象
BoundSql boundSql = ms.getBoundSql(parameterObject);
//主要是为了缓存设计的对象
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
//执行查询数据库操作
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
这里面设置了两个逻辑
1. 获取绑定sql
public BoundSql getBoundSql(Object parameterObject) {
//从sqlSource获取绑定的sql对象
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
//占用传入的参数映射对象,也就是有多少个?就有多少个映射对象
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
//如果没有就新建一个BoundSql对象
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
// check for nested result maps in parameter mappings (issue #30)
//result map相关处理逻辑,目前没有研究
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
又涉及了从sqlSource获取绑定sql,比较复杂的是DynamicSqlSource,涉及了<if>标签等的解析逻辑
@Override
public BoundSql getBoundSql(Object parameterObject) {
//上下文信息,主要封装了参数和sqlBuilder构建对象
DynamicContext context = new DynamicContext(configuration, parameterObject);
//处理sqlNode对象,把sql拼接到sqlBuilder里面去
rootSqlNode.apply(context);
//声明解析器解析#{}的占位符
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
//里面利用了ParameterMappingTokenHandler对#{}进行解析
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
//再获取boundSql,这是解析好的可以发往数据库的sql了。#{}被替换为?了
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
}
return boundSql;
}
2. 获取CacheKey,这个就不解析了,就是缓存使用的
这两步做完以后就进入到了
org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
//配置缓存了就从缓存拿,默认是没配的
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
//调用真正的查询,也就是会先进到BaseExecutor的query方法,在下一段分析
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
Executor(BaseExecutor).query
org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)
@Override
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 <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);
//又放到了一个专门的缓存中,StatementType.CALLABLE的情况下
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
最后就是看doQuery方法了,其他的子类都是覆盖这个进行实现即可,这也就是BaseExecutor存在的模板模式的意义,他封装了一些通用的逻辑,而子类只需要实现即可,不需要再重复的关注这些操作逻辑了
Executor(SimpleExecutor).query
根据前面最终的逻辑就会进入到SimpleExecutor进行执行
org.apache.ibatis.executor.SimpleExecutor#doQuery
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
//获取配置类
Configuration configuration = ms.getConfiguration();
//从配置类中创建StatementHandler对象,默认为PreparedStatementHandler处理器
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//前置处理
stmt = prepareStatement(handler, ms.getStatementLog());
//执行查询
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
是不是好像已经看到了最熟悉的代码了,先获取statement对象,再进行prepare,最后再执行查询,下面就一个个点进去看
获取StatementHandler
又是一个接口,总的来说跟Executor的设计差不多,主要有以下的实现
BaseStatementHandler:基础的实现,提供了一些常用通用的方法
PreparedStatementHandler: 最常用的,继承了BaseStatementHandler
CallableStatementHandler: callable类型,继承了BaseStatementHandler
SimpleStatementHandler: 简单处理器,原生Statement,继承了BaseStatementHandler
RoutingStatementHandler:路由处理器,其实就是把判断代码也封装成一个类管理了,同时保存了以下几个真正的一个实现,调用的时候就是直接调真正的,有兴趣的看一下这个类的实现就明白了,这里就不贴出来了........
以下是创建的流程和逻辑
org.apache.ibatis.session.Configuration#newStatementHandler
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//先创建一个RoutingStatementHandler,其实就是封装了一个具体实现
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
//这里是mybatis插件实现的位置,又进行了插件的拦截代理生成
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
第一步其实很简单,看到构造器和具体实现就明白了
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//根据类型判断同时把他封装给自己,这种有点类似于门面设计模式
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
//默认其实就是这种实现,PreparedStatement类型的
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
里面会使用delegate 去实现接口的所有方法
第二步是代理拦截的生成,之前已经说过了,这里就不再细说了
所以创建这个对象仍然还是比较简单的
prepareStatement处理
org.apache.ibatis.executor.SimpleExecutor#prepareStatement
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
//获取数据库链接,每个sqlSession获取的是同一条,所以也是sqlSession不安全的原因所在
Connection connection = getConnection(statementLog);
//获取statement对象
stmt = handler.prepare(connection, transaction.getTimeout());
//执行参数设置
handler.parameterize(stmt);
//返回statement
return stmt;
}
这里仍然有几个步骤
1. 获取连接,这个没啥好说的
2. 设置基本参数
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
//初始化
statement = instantiateStatement(connection);
//设置超时时间
setStatementTimeout(statement, transactionTimeout);
//设置fetchSize
setFetchSize(statement);
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
3. 也是最重要的,设置参数
org.apache.ibatis.executor.statement.PreparedStatementHandler#parameterize
最终会到达这个方法
org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters
在这里你会看到核心的TypeHanler的使用设置
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
//获取sql占位符对象,有多少个?就有多少个ParameterMapping对象
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
//根据不同情况获取属性值进行设置
Object value;
//参数属性名
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
//获取ParameterMapping对象包含的类型转换器
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
//调用类型转换器设置参数
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
} catch (SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
类型转换器便发生了这里,至于value的取值,目前有些地方我还没搞懂,以后搞懂了再写新的文章进行发布,不过整体逻辑也大概是看下来了
StatementHandler#query
这是最后的一个逻辑,也就是对返回结果的处理,包括怎么封装为对象返回的都在这个里面了,默认使用的是PreparedStatementHandler,也就是我们上面说到的地方
org.apache.ibatis.executor.statement.PreparedStatementHandler#query
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
//转换为PreparedStatement对象
PreparedStatement ps = (PreparedStatement) statement;
//执行查询,这是jdbc原生的api,学过的应该都知道
ps.execute();
//使用ResultSetHandler进行处理结果集
return resultSetHandler.<E> handleResultSets(ps);
}
前面两步还是比较好理解的,最后一部是用于处理结果集的
ResultSetHandler又是一个新的接口,mybatis封装了很多接口,为的是以后方便别人的扩展,所以我们最后只要看ResultSetHandler的DefaultResultSetHandler实现即可,目前只有这个实现,估计大部分人就比较好理解了,再起一个标题块专门来看这个处理集,这个处理方法也是相对比较复杂的,不会说全部,只会说我知道的
handleResultSets方法
而这个默认的是在BaseStatementHandler初始化进行实例化的,可以看到
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//其他的忽略掉了
//参数处理器和结果处理器
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
resultSetHandler.<E> handleResultSets(ps)
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSets
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对象,我们定义的对象被mybatis封装为这个了
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
//校验最少要有一个ResultMap
validateResultMapsCount(rsw, resultMapCount);
//循环处理
while (rsw != null && resultMapCount > resultSetCount) {
//循环获取,里面包含了 private Class<?> type; 这里的type就是User对象
ResultMap resultMap = resultMaps.get(resultSetCount);
//处理结果集,核心方法
handleResultSet(rsw, resultMap, multipleResults, null);
//获取下一个结果集
rsw = getNextResultSet(stmt);
//清除一些数据
cleanUpAfterHandlingResultSet();
//累加
resultSetCount++;
}
//这一块应该是嵌套的resultMap处理,目前没研究..,很久没这么写过了
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
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);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
//进行包装返回,如果是1个直接返回那个,多个还是返回列表
return collapseSingleResultList(multipleResults);
}
上面的逻辑并不复杂,还没有到具体的解析代码,接下来看到处理的代码里面去,handleResultSet方法
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
try {
if (parentMapping != null) {
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else {
//parentMapping为空并且resultHandler为空的逻辑处理,我们现在走的是这里
if (resultHandler == null) {
//声明默认处理器
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
//处理数据同时把数据放到ResultList中
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
//把处理完的数据拿出来
multipleResults.add(defaultResultHandler.getResultList());
} else {
//parentMapping为空并且resultHandler不为空,直接进入到这里来处理,其他的为其他逻辑
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// issue #228 (close resultsets)
closeResultSet(rsw.getResultSet());
}
}
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
//是否有内嵌套的map
if (resultMap.hasNestedResultMaps()) {
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
//目前我们是没有的,所以上面的都不需要看
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
//处理偏移量,我们的逻辑也没用到这个,不过mybatis支持这个.可以用来跳过前多少行数据的功能
//看到这里也让我明白了RowBounds的使用,就是用来跳过前面多少行的
skipRows(rsw.getResultSet(), rowBounds);
//调用Result.next开始获取数据进行处理了
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
//获取一行数据
Object rowValue = getRowValue(rsw, discriminatedResultMap);
//保存处理好的数据
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
if (parentMapping != null) {
linkToParents(rs, parentMapping, rowValue);
} else {
//
callResultHandler(resultHandler, resultContext, rowValue);
}
}
@SuppressWarnings("unchecked" /* because ResultHandler<?> is always ResultHandler<Object>*/)
private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {
//把获取的数据放到下一个去
resultContext.nextResultObject(rowValue);
//回调处理把数据放到调用进来的List<Object>中去,这也是一种设计思想,回调模式!
((ResultHandler<Object>) resultHandler).handleResult(resultContext);
}
那么现在的逻辑也是越来越清晰了,解析数据就发生在getRowValue方法中,我们再去里面看看发生了什么
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
//创建结果返回对象,这里也就是调用反射创建了User对象,这个时候还没有附上值
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
//生成类元数据,提供了很多方便操作对象的方法
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (shouldApplyAutomaticMappings(resultMap, false)) {
//经过这个方法后才附上了值,所以处理逻辑肯定是发生在这个里面了
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
}
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
再接着往下看
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
//创建还未自动匹配的字段列
List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
boolean foundValues = false;
if (!autoMapping.isEmpty()) {
//循环处理
for (UnMappedColumnAutoMapping mapping : autoMapping) {
//这里就可以看到类型转换器的调用了,通过类型转换器去获取具体的值出来
final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
if (value != null) {
foundValues = true;
}
if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
// gcode issue #377, call setter on nulls (value is not 'found')
//把数据设置到对象中
metaObject.setValue(mapping.property, value);
}
}
}
return foundValues;
}
这里再一次看到了类型转换器的设置,同时也看到了使用反射设置对象数据,那么到这里整个逻辑就已经结束了
其他的就是一些分支处理,或者说细节处理,细节的话有兴趣可以再到对应的方法里面去进行分析,这里整个流程差不多就要结束了
last
前面的结果查询后就又回到这个方法了
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);
//又放到了一个专门的缓存中,StatementType.CALLABLE的情况下
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
到处,整个流程就分析完了,也不知道大家能不能看懂我说的...