mybatis中selectOne方法分析

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

0首先获取sqlSession,大致流程如下

SqlSessionFactoryBuilder->SqlSessionFactory

SimpleExecutor . <- BaseExecutor<- Executor

CachingExecutor <-Executor

SqlSession session=sqlSessionFactory.openSession();

DefaultSqlSession类

 

@Override

public T selectOne(String statement, Object parameter) {

// Popular vote was to return null on 0 results and throw exception on too many.

//转而去调用selectList,很简单的,如果得到0条则返回null,得到1条则返回1条,得到多条报TooManyResultsException错

// 特别需要主要的是当没有查询到结果的时候就会返回null。因此一般建议在mapper中编写resultType的时候使用包装类型

//而不是基本类型,比如推荐使用Integer而不是int。这样就可以避免NPE

List list = this.selectList(statement, parameter);

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;

}

}

 

 

//核心selectList

@Override

public List selectList(String statement, Object parameter, RowBounds rowBounds) {

try {

//根据statement id找到对应的MappedStatement

MappedStatement ms = configuration.getMappedStatement(statement);

//转而用执行器来查询结果,注意这里传入的ResultHandler是null

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();

}

}

 

CachingExecutor类

@Override

public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {

BoundSql boundSql = ms.getBoundSql(parameterObject);

//query时传入一个cachekey参数

CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);

return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

}

 

 

 

@Override

public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)

throws SQLException {

Cache cache = ms.getCache();

//默认情况下是没有开启缓存的(二级缓存).要开启二级缓存,你需要在你的 SQL 映射文件中添加一行:

//简单的说,就是先查CacheKey,查不到再委托给实际的执行器去查

if (cache != null) {

flushCacheIfRequired(ms);

if (ms.isUseCache() && resultHandler == null) {

ensureNoOutParams(ms, parameterObject, boundSql);

@SuppressWarnings("unchecked")

List list = (List) tcm.getObject(cache, key);

if (list == null) {

list = delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

tcm.putObject(cache, key, list); // issue #578 and #116

}

return list;

}

}

return delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

}

 

 

 

BaseExecutor类

@SuppressWarnings("unchecked")

@Override

public List 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.");

}

//先清局部缓存,再查询.但仅查询堆栈为0,才清。为了处理递归调用

if (queryStack == 0 && ms.isFlushCacheRequired()) {

clearLocalCache();

}

List list;

try {

//加一,这样递归调用到上面的时候就不会再清局部缓存了

queryStack++;

//先根据cachekey从localCache去查

list = resultHandler == null ? (List) localCache.getObject(key) : null;

if (list != null) {

//若查到localCache缓存,处理localOutputParameterCache

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

//如果是STATEMENT,清本地缓存

clearLocalCache();

}

}

return list;

}

 

 

 

 

//从数据库查

private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {

List list;

//先向缓存中放入占位符???

localCache.putObject(key, EXECUTION_PLACEHOLDER);

try {

list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);

} finally {

//最后删除占位符

localCache.removeObject(key);

}

//加入缓存

localCache.putObject(key, list);

//如果是存储过程,OUT参数也加入缓存

if (ms.getStatementType() == StatementType.CALLABLE) {

localOutputParameterCache.putObject(key, parameter);

}

return list;

}

 

@Override

public List handleResultSets(Statement stmt) throws SQLException {

ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

final List multipleResults = new ArrayList();

 

int resultSetCount = 0;

ResultSetWrapper rsw = getFirstResultSet(stmt);

 

List resultMaps = mappedStatement.getResultMaps();

//一般resultMaps里只有一个元素

int resultMapCount = resultMaps.size();

validateResultMapsCount(rsw, resultMapCount);

while (rsw != null && resultMapCount > resultSetCount) {

ResultMap resultMap = resultMaps.get(resultSetCount);

handleResultSet(rsw, resultMap, multipleResults, null);

rsw = getNextResultSet(stmt);

cleanUpAfterHandlingResultSet();

resultSetCount++;

}

 

String[] resultSets = mappedStatement.getResulSets();

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++;

}

}

return collapseSingleResultList(multipleResults);

}

 

转载于:https://my.oschina.net/iioschina/blog/1860153

你可能感兴趣的:(mybatis中selectOne方法分析)