Mybatis源码 select分析
来源:互联网 发布:显卡品牌 知乎 编辑:程序博客网 时间:2024/05/30 23:44
在我们上一篇的分析中分析了Mybatis一次插入执行流程分析,因为我们所有的插入执行都会转换为update,所以这一次我们执行一次我们的查询,看看他的过程是怎么样的?代码如下
Student student = studentMapper.selectStudentWithAddress(1);
这段代码跟踪,因为他是一个代理我们直接走进代理,和上一篇分析的一样在excute中有一个select的判断:
else if (SqlCommandType.SELECT == command.getType()) { if (method.returnsVoid() && method.hasResultHandler()) { executeWithResultHandler(sqlSession, args); result = null; } else if (method.returnsMany()) { result = executeForMany(sqlSession, args); } else if (method.returnsMap()) { result = executeForMap(sqlSession, args); } else { Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); }
我们选择进入一个
result = executeForMany(sqlSession, args);
进入executeForMany的代码中:
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) { List<E> result;//结果集 Object param = method.convertArgsToSqlCommandParam(args);//转换参数 if (method.hasRowBounds()) {//是否有行数限制 RowBounds rowBounds = method.extractRowBounds(args); result = sqlSession.<E>selectList(command.getName(), param, rowBounds); } else { result = sqlSession.<E>selectList(command.getName(), param); } // 对结果集进行处理 if (!method.getReturnType().isAssignableFrom(result.getClass())) { if (method.getReturnType().isArray()) { return convertToArray(result); } else { return convertToDeclaredCollection(sqlSession.getConfiguration(), result); } } return result; }
上面的代码归纳起来:
1。转换参数
2。判断是否有行数限制,来执行不同的查询。
3。对返回的结果进行一些处理,如果需要数组转换为数组,否则转化为申明的结果集。
我们这里跟踪
result = sqlSession.<E>selectList(command.getName(), param, rowBounds);
继续进入我们的sqlSession的代码:
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { MappedStatement ms = configuration.getMappedStatement(statement);//获取我们的映射Statement 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(); } }
executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);这句是我们的核心执行,和以前分析的一样我们要记住我们所有对的真正执行过程都是在executor中执行的。
简单说明一下wrapCollection(parameter),把我们的参数包装为一个map.接下来进入query:
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameter);//得到真正的sql CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);//得到我们之前的缓存Key return query(ms, parameter, rowBounds, resultHandler, key, boundSql); }
ms.getBoundSql(parameter)这里是我们解析sql的地方上一篇已经说过,这里不便多谈。接下来得到我们的缓存key如果在同一次SqlSession中我们就会缓存查询数据:
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; }
过程简述为
1。上面的代码有一个int类型的查询栈用来标记当前是否是第一次查询,如果是就清除当前的缓存。
2。在执行查询之前首先查询栈自加1。
3。判断结果集处理器是否为空,如果为空则从缓存中获取,如果不为空则赋值为null。
4。进入queryFromDatabase查询。
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; }
核心执行:
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
模板方法,我们进入默认的SimpleExecutor.class的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 handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } }
和插入一样,这里的Handler是个代理,在执行真正的查询之前我们可以在这里进行分页拦截,后面我也会详细分析如何写一个mybati的分页拦截器。
- Mybatis源码 select分析
- 【MyBatis源码分析】select源码分析及小结
- 【Mybatis】mybatis插件源码分析
- Mybatis工作机制源码分析—一次select请求处理流程
- MyBatis 3源码分析
- MyBatis源码分析
- mybatis源码分析
- Mybatis原理源码分析
- Mybatis源码分析
- MyBatis源码分析
- Mybatis源码分析--MapperScannerConfigurer
- Mybatis源码分析系列
- MyBatis Generator 源码分析
- Mybatis源码分析
- Mybatis源码分析-数据源
- Mybatis源码分析-二级缓存
- Spring-Mybatis源码分析
- Mybatis 源码分析
- Freeswitch 高级主题之用kamailio负载均衡
- eclipes中安卓创建虚拟的OK按钮不能点
- 白话空间统计番外:再谈P值
- Java对象的引用方式(强引用, 软引用, 弱引用, 虚引用)
- C++ error: default argument given for parameter 1
- Mybatis源码 select分析
- java多态中的向上转型和向下转型
- 慕司板资源汇总
- git tips
- Tsinsen A1120 拦截导弹
- C/C++—— C++中构造函数不能是虚函数的原因分析
- 欢迎使用CSDN-markdown编辑器
- 《Java并发编程的艺术》读书笔记:Fork/Join框架
- IOS-MBProgressHUD常见的几种用法