• (3)一起来看下使用mybatis框架的select语句的源码执行流程吧


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

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

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

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

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

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

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

    继续点进去看

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

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

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

    //这里method是接口DemoMapper的selectAll方法
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
          // 如果目标方法是Object类继承来的,直接调用目标方法
          //method.getDeclaringClass()是接口DemoMapper的类对象,这里结果为false,跳过这一步
          if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
            //这里method是接口DemoMapper的selectAll方法,所以结果也为false,跳过这一步
          } else if (method.isDefault()) {
            if (privateLookupInMethod == null) {
              return invokeDefaultMethodJava8(proxy, method, args);
            } else {
              return invokeDefaultMethodJava9(proxy, method, args);
            }
          }
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
        //这里将method放入缓存
        // 从缓存中获取MapperMethod 对象,如果没有就创建新的并添加
        final MapperMethod mapperMethod = cachedMapperMethod(method);
        //这是真正的执行方法
        return mapperMethod.execute(sqlSession, args);
      }
    缓存的东西,我们下次再说,我们继续点进去看
    //就是这个执行方法
      public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;
        //command.getType()此时是select
        switch (command.getType()) {
          case INSERT: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.insert(command.getName(), param));
            break;
          }
          case UPDATE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.update(command.getName(), param));
            break;
          }
          case DELETE: {
            Object param = method.convertArgsToSqlCommandParam(args);
            result = rowCountResult(sqlSession.delete(command.getName(), param));
            break;
          }
          //进入这个分支
          case SELECT:
            //这里结果为false,不进这里
            if (method.returnsVoid() && method.hasResultHandler()) {
              executeWithResultHandler(sqlSession, args);
              result = null;
              //这里结果为真,进这里
            } else if (method.returnsMany()) {
              result = executeForMany(sqlSession, args);
              //这里结果为false,不进这里
            } else if (method.returnsMap()) {
              result = executeForMap(sqlSession, args);
              //这里结果为false,不进这里
            } else if (method.returnsCursor()) {
              result = executeForCursor(sqlSession, args);
            } else {
              //
              Object param = method.convertArgsToSqlCommandParam(args);
              //处理参数完成后后param是hashmap类型,key有两种,一种是#{}里面的参数名,
              // 另一种是(param1, param2, ...),value只有一种,就是我们的实际参数
              //这里执行sql得到查询结果result,跟进去看下
              result = sqlSession.selectOne(command.getName(), param);
              if (method.returnsOptional()
                  && (result == null || !method.getReturnType().equals(result.getClass()))) {
                result = Optional.ofNullable(result);
              }
            }
            break;
          case FLUSH:
            result = sqlSession.flushStatements();
            break;
          default:
            throw new BindingException("Unknown execution method for: " + command.getName());
        }
        if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
          throw new BindingException("Mapper method '" + command.getName()
              + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
        }
        return result;
      }

    继续往下看

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

    继续

    //这个是真正的sql执行方法了,statement是具体的方法名com.lusaisai.dao.DemoMapper.selectOne
      //parameter是参数名和真是的参数
      @Override
      public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        try {
          //configuration对象根据statement,得到关于sql语句的相关信息
          //这里得到的ms包含sql语句
          MappedStatement ms = configuration.getMappedStatement(statement);
          //这里就是执行sql语句
          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();
        }
      }

    继续跟

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

    这里继续

    @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;
        //key值就是待执行的sql
        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;
      }

    继续

    @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.query(stmt, resultHandler);
        } finally {
          closeStatement(stmt);
        }
      }

    跟一下return那行

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

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

    public List<Object> handleResultSets(Statement stmt) throws SQLException {
        ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
    
        final List<Object> multipleResults = new ArrayList<>();
    
        int resultSetCount = 0;
        ResultSetWrapper rsw = getFirstResultSet(stmt);
    
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        int resultMapCount = resultMaps.size();
        validateResultMapsCount(rsw, resultMapCount);
        while (rsw != null && resultMapCount > resultSetCount) {
          ResultMap resultMap = resultMaps.get(resultSetCount);
          handleResultSet(rsw, resultMap, multipleResults, null);
          //这里已经执行完sql,生成结果集了
          rsw = getNextResultSet(stmt);
          cleanUpAfterHandlingResultSet();
          resultSetCount++;
        }
    
        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++;
          }
        }
    
        return collapseSingleResultList(multipleResults);
      }

    继续跟我注释的那行

    private ResultSetWrapper getNextResultSet(Statement stmt) {
        // Making this method tolerant of bad JDBC drivers
        try {
          if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
            // Crazy Standard JDBC way of determining if there are more results
            //这里的stmt已经包含可执行的sql了
            if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {
              ResultSet rs = stmt.getResultSet();
              if (rs == null) {
                return getNextResultSet(stmt);
              } else {
                return new ResultSetWrapper(rs, configuration);
              }
            }
          }
        } catch (Exception e) {
          // Intentionally ignored.
        }
        return null;
      }

    最后再贴张网上找的图

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

  • 相关阅读:
    qt creator中输入中文中文变繁体
    Trie
    pycharm 专业版的 django功能
    fzu 1533
    django使用问题记录
    查看SQLServer最耗资源时间的SQL语句
    从mysql数据库删除重复记录只保留其中一条(保留id最小的一条)
    使用CSS3的appearance属性改变元素的外观
    mysql中将多行数据合并成一行数据
    MySQL字符串的拼接、截取、替换、查找位置
  • 原文地址:https://www.cnblogs.com/lusaisai/p/11632650.html
Copyright © 2020-2023  润新知