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

SqlSessionFactoryBuilder->SqlSessionFactory

SimpleExecutor .

CachingExecutor

SqlSession session=sqlSessionFactory.openSession();

DefaultSqlSession类

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

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类

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

}

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

}

one方法报错 select_mybatis中selectOne方法分析相关推荐

  1. java中write方法报错_Java中管道报错:Write end dead

    今天看了下关于管道的通信,Java中的管道只能在同一进程的不同线程间通信.今天测试两个线程进行通信发现报错.下面是我测试的代码. package com.wpl.testIO; import java ...

  2. python3中input()方法报错traceback变量未定义的解决方法

    python3中input()方法报错traceback变量未定义的解决方法 参考文章: (1)python3中input()方法报错traceback变量未定义的解决方法 (2)https://ww ...

  3. vue父组件调用子组件方法报错的解决方法

    vue父组件调用子组件方法报错 在父组件定义了一个tab标签页,每一个标签页下面都调用不同的组件,如下图所示: 子组件中定义的方法: setup() {const getList = () => ...

  4. Python调用seek(pos,mode)方法报错Can‘t do nonzero cur-relative seeks

    在Python中IO操作调用seek(pos,mode)方法时,出现异常错误:OSError:Can't do nonzero cur-relative seeks其示例代码如下: from io i ...

  5. 基于adversarial-robustness-toolbox(ART)包进行AI对抗攻击ZOO攻击方法报错

    基于adversarial-robustness-toolbox(ART)包进行AI对抗攻击ZOO攻击方法报错 环境 问题分析 问题解决 ZooAttack类使用扩展 环境 ART版本:1.14.0 ...

  6. getSupportFragmentManager().beginTransaction().add方法报错

    图中红线报错时,发现明明一样但是无论如何改都会报错,这时候就要注意Fragment文件的extends导入的方法,它可能是导入的包不对 如图所示,Fragment有两个包,如果导入的是Android. ...

  7. java 实现接口后重写方法报错

    java 实现接口后重写方法报错 java 实现接口后重写方法报错 The method contextDestroyed(ServletContextEvent) of type InitListe ...

  8. uEditor setContent方法报错Uncaught TypeError: Cannot read property ‘innerHTML‘ of undefined

    uEditor setContent方法报错Uncaught TypeError: Cannot read property 'innerHTML' of undefined 报错信息 解决方法 报错 ...

  9. 快速解决Android studio native 方法报错

    反编译一个游戏项目,发现native方法报错.如图: 项目是通过加载动态链接库so,没有jni的源码,导致native方法有红色波浪线,我们可以关闭android studio的jni支持. 点击An ...

最新文章

  1. pythongui登录界面密码显示_python的GUI之一个简单的登录界面
  2. ERP与GMP结合在药类企业实施及应用
  3. GitLab 8.3.3 发布 开源代码管理
  4. css那些事儿4 背景图像
  5. SkyEye——汽车电子系统仿真测试工具
  6. WGZX:javaScript 学习心得--1
  7. 网站登录页面php代码,一个简单的网页密码登陆php代码
  8. java20 创建服务器:ServerSocket
  9. android菜单详解四:子菜单
  10. I00028 整数逆序
  11. scanf 与 scanf_s
  12. Java(面向对象OOP)
  13. GIS相关网站、社区、论坛收藏
  14. M/M/m排队模型 (单队列多服务台并联服务模型)数学建模: 基于生灭过程的理论计算和基于事件推进的Matlab模拟仿真思路
  15. vue 创建项目使用npm还是yarn
  16. 形式验证——学习笔记
  17. oracle10安装完成之后测试,RHEL4U4和RHEL5安装oracle10g(测试过绝对可以成功)
  18. DuckDuckGo将与整合Apple Maps有更丰富的地图信息及隐私
  19. 云服务器微信faq,微信公众平台常见问题FAQ
  20. 超好的赚钱方法 目前广告点击报酬最高的

热门文章

  1. windows强制安装IE浏览器
  2. 爬虫Scrapy框架学习(三)-爬取苏宁图书信息案例
  3. 【35. 多重背包】
  4. SplunkEnterprise日志服务程序/SplunkForward通用转发器部署客户端
  5. MySQL 联级删除(on delete cascade)应用
  6. Linux下C编程入门(1)
  7. Crescendo:适用于macOS的实时事件查看器(2020)
  8. 微信远程代码执行漏洞(最新版本利用)-亲测已上线
  9. Python掘金3量化交易代码:判断当前持仓,如果是今天买的不能卖
  10. C#字符串- string.Format格式化