本文是作者原创,版权归作者所有.若要转载,请注明出处.本文以简单的select语句为例,只贴我觉得比较重要的源码,其他不重要非关键的就不贴了

主流程和insert语句差不多,这里主要讲不同的流程,前面配置解析就不看了

  1. SqlSession sqlSession = sqlSessionFactory.openSession();
  2. //通过动态代理实现接口 ,用动态代理对象去帮我们执行SQL
  3. //这里生成mapper实际类型是org.apache.ibatis.binding.MapperProxy
  4. DemoMapper mapper = sqlSession.getMapper(DemoMapper.class);
  5. //这里用生成的动态代理对象执行
  6. String projId="0124569b738e405fb20b68bfef37f487";
  7. String sectionName="标段";
  8. List<ProjInfo> projInfos = mapper.selectAll(projId, sectionName);
  9. System.out.println(projInfos);
  10. //sqlSession.commit();
  11. sqlSession.close();

点进去,看下方法sqlSession.getMapper(DemoMapper.class),这个调到下面这个方法

  1. public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  2. //这里就是动态代理生成的代理对象
  3. final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
  4. if (mapperProxyFactory == null) {
  5. throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
  6. }
  7. try {
  8. return mapperProxyFactory.newInstance(sqlSession);
  9. } catch (Exception e) {
  10. throw new BindingException("Error getting mapper instance. Cause: " + e, e);
  11. }
  12. }

我们看下mapperProxyFactory.newInstance(sqlSession)这个方法

  1. public T newInstance(SqlSession sqlSession) {
  2. final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
  3. return newInstance(mapperProxy);
  4. }

继续点进去看

  1. protected T newInstance(MapperProxy<T> mapperProxy) {
  2. return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  3. }

好,很明显了,这里用的jdk的动态代理,关于动态代理,这里就不赘述了,下次有机会在设计模式里专门讲一下.所以这里返回的是代理对象

继续往下看,我们看mapper.selectAll(projId, sectionName)这个方法debug进去,调的是jdk动态代理的invoke方法,里面就是具体的查询逻辑了

  1. //这里method是接口DemoMapper的selectAll方法
  2. @Override
  3. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  4. try {
  5. // 如果目标方法是Object类继承来的,直接调用目标方法
  6. //method.getDeclaringClass()是接口DemoMapper的类对象,这里结果为false,跳过这一步
  7. if (Object.class.equals(method.getDeclaringClass())) {
  8. return method.invoke(this, args);
  9. //这里method是接口DemoMapper的selectAll方法,所以结果也为false,跳过这一步
  10. } else if (method.isDefault()) {
  11. if (privateLookupInMethod == null) {
  12. return invokeDefaultMethodJava8(proxy, method, args);
  13. } else {
  14. return invokeDefaultMethodJava9(proxy, method, args);
  15. }
  16. }
  17. } catch (Throwable t) {
  18. throw ExceptionUtil.unwrapThrowable(t);
  19. }
  20. //这里将method放入缓存
  21. // 从缓存中获取MapperMethod 对象,如果没有就创建新的并添加
  22. final MapperMethod mapperMethod = cachedMapperMethod(method);
  23. //这是真正的执行方法
  24. return mapperMethod.execute(sqlSession, args);
  25. }
  1. 缓存的东西,我们下次再说,我们继续点进去看
  1. //就是这个执行方法
  2. public Object execute(SqlSession sqlSession, Object[] args) {
  3. Object result;
  4. //command.getType()此时是select
  5. switch (command.getType()) {
  6. case INSERT: {
  7. Object param = method.convertArgsToSqlCommandParam(args);
  8. result = rowCountResult(sqlSession.insert(command.getName(), param));
  9. break;
  10. }
  11. case UPDATE: {
  12. Object param = method.convertArgsToSqlCommandParam(args);
  13. result = rowCountResult(sqlSession.update(command.getName(), param));
  14. break;
  15. }
  16. case DELETE: {
  17. Object param = method.convertArgsToSqlCommandParam(args);
  18. result = rowCountResult(sqlSession.delete(command.getName(), param));
  19. break;
  20. }
  21. //进入这个分支
  22. case SELECT:
  23. //这里结果为false,不进这里
  24. if (method.returnsVoid() && method.hasResultHandler()) {
  25. executeWithResultHandler(sqlSession, args);
  26. result = null;
  27. //这里结果为真,进这里
  28. } else if (method.returnsMany()) {
  29. result = executeForMany(sqlSession, args);
  30. //这里结果为false,不进这里
  31. } else if (method.returnsMap()) {
  32. result = executeForMap(sqlSession, args);
  33. //这里结果为false,不进这里
  34. } else if (method.returnsCursor()) {
  35. result = executeForCursor(sqlSession, args);
  36. } else {
  37. //
  38. Object param = method.convertArgsToSqlCommandParam(args);
  39. //处理参数完成后后param是hashmap类型,key有两种,一种是#{}里面的参数名,
  40. // 另一种是(param1, param2, ...),value只有一种,就是我们的实际参数
  41. //这里执行sql得到查询结果result,跟进去看下
  42. result = sqlSession.selectOne(command.getName(), param);
  43. if (method.returnsOptional()
  44. && (result == null || !method.getReturnType().equals(result.getClass()))) {
  45. result = Optional.ofNullable(result);
  46. }
  47. }
  48. break;
  49. case FLUSH:
  50. result = sqlSession.flushStatements();
  51. break;
  52. default:
  53. throw new BindingException("Unknown execution method for: " + command.getName());
  54. }
  55. if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
  56. throw new BindingException("Mapper method '" + command.getName()
  57. + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
  58. }
  59. return result;
  60. }

继续往下看

  1. 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.selectList(command.getName(), param, rowBounds);
    } else {
    //进这里,点进去看
    result = sqlSession.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;
    }

继续

  1. //这个是真正的sql执行方法了,statement是具体的方法名com.lusaisai.dao.DemoMapper.selectOne
  2. //parameter是参数名和真是的参数
  3. @Override
  4. public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  5. try {
  6. //configuration对象根据statement,得到关于sql语句的相关信息
  7. //这里得到的ms包含sql语句
  8. MappedStatement ms = configuration.getMappedStatement(statement);
  9. //这里就是执行sql语句
  10. return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
  11. } catch (Exception e) {
  12. throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
  13. } finally {
  14. ErrorContext.instance().reset();
  15. }
  16. }

继续跟

  1. //执行语句这个方法,跟进去看下
  2. @Override
  3. public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
  4. //
  5. BoundSql boundSql = ms.getBoundSql(parameterObject);
  6. CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
  7. //这个跟进去看戏,应该是真正的jdbc操作了
  8. return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  9. }

继续

  1. @Override
  2. public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
  3. throws SQLException {
  4. Cache cache = ms.getCache();
  5. if (cache != null) {
  6. flushCacheIfRequired(ms);
  7. if (ms.isUseCache() && resultHandler == null) {
  8. ensureNoOutParams(ms, boundSql);
  9. @SuppressWarnings("unchecked")
  10. List<E> list = (List<E>) tcm.getObject(cache, key);
  11. if (list == null) {
  12. list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  13. tcm.putObject(cache, key, list); // issue #578 and #116
  14. }
  15. return list;
  16. }
  17. }
  18. //前面是缓存处理跟进去
  19. return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  20. }

这里继续

  1. @Override
  2. public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  3. ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
  4. if (closed) {
  5. throw new ExecutorException("Executor was closed.");
  6. }
  7. if (queryStack == 0 && ms.isFlushCacheRequired()) {
  8. clearLocalCache();
  9. }
  10. List<E> list;
  11. try {
  12. queryStack++;
  13. list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
  14. if (list != null) {
  15. handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
  16. } else {
  17. //进这里,继续跟
  18. list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
  19. }
  20. } finally {
  21. queryStack--;
  22. }
  23. if (queryStack == 0) {
  24. for (DeferredLoad deferredLoad : deferredLoads) {
  25. deferredLoad.load();
  26. }
  27. // issue #601
  28. deferredLoads.clear();
  29. if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
  30. // issue #482
  31. clearLocalCache();
  32. }
  33. }
  34. return list;
  35. }

继续

  1. private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  2. List<E> list;
  3. //key值就是待执行的sql
  4. localCache.putObject(key, EXECUTION_PLACEHOLDER);
  5. try {
  6. //跟进去
  7. list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
  8. } finally {
  9. localCache.removeObject(key);
  10. }
  11. localCache.putObject(key, list);
  12. if (ms.getStatementType() == StatementType.CALLABLE) {
  13. localOutputParameterCache.putObject(key, parameter);
  14. }
  15. return list;
  16. }

继续

  1. @Override
  2. public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  3. Statement stmt = null;
  4. try {
  5. Configuration configuration = ms.getConfiguration();
  6. StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
  7. stmt = prepareStatement(handler, ms.getStatementLog());
  8. return handler.query(stmt, resultHandler);
  9. } finally {
  10. closeStatement(stmt);
  11. }
  12. }

跟一下return那行

  1. @Override
  2. public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  3. //这里强转成预编译对象PreparedStatement
  4. PreparedStatement ps = (PreparedStatement) statement;
  5. ps.execute();
  6. return resultSetHandler.handleResultSets(ps);
  7. }

好,我们看到PreparedStatement对象了,继续

  1. public List<Object> handleResultSets(Statement stmt) throws SQLException {
  2. ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
  3.  
  4. final List<Object> multipleResults = new ArrayList<>();
  5.  
  6. int resultSetCount = 0;
  7. ResultSetWrapper rsw = getFirstResultSet(stmt);
  8.  
  9. List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  10. int resultMapCount = resultMaps.size();
  11. validateResultMapsCount(rsw, resultMapCount);
  12. while (rsw != null && resultMapCount > resultSetCount) {
  13. ResultMap resultMap = resultMaps.get(resultSetCount);
  14. handleResultSet(rsw, resultMap, multipleResults, null);
  15. //这里已经执行完sql,生成结果集了
  16. rsw = getNextResultSet(stmt);
  17. cleanUpAfterHandlingResultSet();
  18. resultSetCount++;
  19. }
  20.  
  21. String[] resultSets = mappedStatement.getResultSets();
  22. if (resultSets != null) {
  23. while (rsw != null && resultSetCount < resultSets.length) {
  24. ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
  25. if (parentMapping != null) {
  26. String nestedResultMapId = parentMapping.getNestedResultMapId();
  27. ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
  28. handleResultSet(rsw, resultMap, null, parentMapping);
  29. }
  30. rsw = getNextResultSet(stmt);
  31. cleanUpAfterHandlingResultSet();
  32. resultSetCount++;
  33. }
  34. }
  35.  
  36. return collapseSingleResultList(multipleResults);
  37. }

继续跟我注释的那行

  1. private ResultSetWrapper getNextResultSet(Statement stmt) {
  2. // Making this method tolerant of bad JDBC drivers
  3. try {
  4. if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
  5. // Crazy Standard JDBC way of determining if there are more results
  6. //这里的stmt已经包含可执行的sql了
  7. if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {
  8. ResultSet rs = stmt.getResultSet();
  9. if (rs == null) {
  10. return getNextResultSet(stmt);
  11. } else {
  12. return new ResultSetWrapper(rs, configuration);
  13. }
  14. }
  15. }
  16. } catch (Exception e) {
  17. // Intentionally ignored.
  18. }
  19. return null;
  20. }

最后再贴张网上找的图

好,到这里我们已经看完执行流程,其实封装了很多层,并没有全都要搞懂的必要,这里的重点是用了动态代理,底层肯定是jdbc操作,当然它还加了很多缓存和各种验证的代码.关于缓存的源码,有机会下次再看吧.

(3)一起来看下使用mybatis框架的select语句的源码执行流程吧的更多相关文章

  1. mybatis源码专题(2)--------一起来看下使用mybatis框架的insert语句的源码执行流程吧

    本文是作者原创,版权归作者所有.若要转载,请注明出处.本文以简单的insert语句为例 1.mybatis的底层是jdbc操作,我们先来回顾一下insert语句的执行流程,如下 执行完后,我们看下数据 ...

  2. 深入Mybatis源码——执行流程

    前言 上一篇分析Mybatis是如何加载解析XML文件的,本篇紧接上文,分析Mybatis的剩余两个阶段:代理封装和SQL执行. 正文 代理封装 Mybatis有两种方式调用Mapper接口: pri ...

  3. Mybatis底层源码执行流程

    1.通过类加载器,加载了config.xml文件 2.通过SqlSessionFactoryBuilder.build(resource)这个方法进行了config.xml的解析,解析为Configu ...

  4. 详解Java的MyBatis框架中SQL语句映射部分的编写

    这篇文章主要介绍了Java的MyBatis框架中SQL语句映射部分的编写,文中分为resultMap和增删查改实现两个部分来讲解,需要的朋友可以参考下 1.resultMap SQL 映射XML 文件 ...

  5. MVC系列——MVC源码学习:打造自己的MVC框架(二:附源码)

    前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥.今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个 ...

  6. 详解Mybatis拦截器(从使用到源码)

    详解Mybatis拦截器(从使用到源码) MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能. 本文从配置到源码进行分析. 一.拦截器介绍 MyBatis 允许你在 ...

  7. Ext.NET 4.1 系统框架的搭建(后台) 附源码

    Ext.NET 4.1 系统框架的搭建(后台) 附源码 代码运行环境:.net 4.5  VS2013 (代码可直接编译运行) 预览图: 分析图: 上面系统的构建包括三块区域:North.West和C ...

  8. Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析

    经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习 ...

  9. 从零开始手写 spring ioc 框架,深入学习 spring 源码

    IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过 ...

随机推荐

  1. springboot+apache前后端分离部署https

    目录 1. 引言 2. 了解https.证书.openssl及keytool 2.1 https 2.1.1 什么是https 2.1.2 https解决什么问题 2.2 证书 2.2.1 证书内容 ...

  2. 重磅!普惠AI--华为云语音语义万次调用1元购,有奖问答@评论区等你来!【华为云技术分享】

    活动快速入口:https://activity.huaweicloud.com/language_speech_promotion0.html 语音交互与自然语言处理 语音交互是一种人机交互方式,以开 ...

  3. 这个七夕节,用Python为女友绘制一张爱心照片墙吧!【华为云技术分享】

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字“加群”,加入华为云线上技术讨论群:输入关键字“最新活动”,获取华为云最新特惠促销.华为云诸多技术大咖.特 ...

  4. shell 往文件中添加一列一样的字符串

    例如:往文件file.txt中,添加一列字符串"20161020", 用制表符分割 awk '$0=$0"\t20161020"' file.txt

  5. 分享一个Vue数组赋值的错误

    今天在写项目用到Vue的时候,遇到的一个问题,纠结了好一会,首先我的代码是这样的 有没有毛病!!  开始我感觉是没啥毛病啊,按照之前写Java代码的逻辑,我感觉这没一点毛病 . 但是它就是有毛病, 假 ...

  6. 洛谷 题解 P1842 【奶牛玩杂技】

    本蒟蒻又双叒叕被爆踩辣! Solution: 我们先看数据,50000,那么O(n)或者O(n log(n))是可以过的,非严格O(n * sqrt(n))要卡卡常,说不定也可以过. 那么什么算法可以 ...

  7. echarts 堆叠柱状图 + 渐变柱状图

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. spring security 权限安全认证框架-入门(一)

    spring security 概述: Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架.它是保护基于spring的应用程序的实际标准. Spring Security ...

  9. 小程序 - 解决IOS端使用css滤镜渲染出现异常

    在页面渲染时,GPU默认不会开启.当css样式中出现某些规则时,就会开启GPU加速,让动画运行的更加流畅,最显著的象征就是元素的3D变换. 这些就是我们通常所说的css硬件加速,但我们有时候并不需要用 ...

  10. Nios II的Boot过程分析

    目录 1       概述....................................................................... 1 2       几种常见的 ...