Mybatis---学习过程---Mybatis架构原理之executor执行原理

Mybatis—学习过程—Mybatis架构原理之executor执行原理

1.继续进行源码中selectList中的步骤,进入executor.query()

  1. 点击query方法,进入实现类BaseExecutor
        //此方法在SimpleExecutor的父类BaseExecutor中实现
        @Override
        public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
            //根据传入的参数动态获得SQL语句,最后返回用BoundSql对象表示
            BoundSql boundSql = ms.getBoundSql(parameter);
            //为本次查询创建缓存的Key
            CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
            // 查询
            return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
        }
    
        @SuppressWarnings("unchecked")
        @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());
            // 判断执行器是否已经关闭,则抛出 ExecutorException 异常
            if (closed) {
                throw new ExecutorException("Executor was closed.");
            }
            // 清空本地缓存,如果 queryStack 为零,并且要求清空本地缓存。
            if (queryStack == 0 && ms.isFlushCacheRequired()) {
                clearLocalCache();
            }
            List<E> list;
            try {
                // queryStack + 1
                queryStack++;
                // Mybatis的一级缓存默认开启,根据刚才创建的catchKey从一级缓存中,获取查询结果
                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 - 1
                queryStack--;
            }
            if (queryStack == 0) {
                // 执行延迟加载
                for (DeferredLoad deferredLoad : deferredLoads) {
                    deferredLoad.load();
                }
                // issue #601
                // 清空 deferredLoads
                deferredLoads.clear();
                // 如果缓存级别是 LocalCacheScope.STATEMENT ,则进行清理
                if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                    // issue #482
                    clearLocalCache();
                }
            }
            return list;
        }
    
  2. 点击queryFromDatabase进入方法,在一级缓存中没查到就到到数据库中查的方法
    // 从数据库中读取操作
    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        List<E> list;
        // 在缓存中,添加占位对象。此处的占位符,和延迟加载有关,可见 `DeferredLoad#canLoad()` 方法
        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;
    }
    
  3. 点击doQuery进入SimpleExecutor实现类中的doQuery方法,可以看到执行器最终是将查询的操作过程交给了StatementHandler对象来处理
    @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();
            // 传入参数创建StatementHanlder对象来执行查询
            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            // 创建jdbc中的statement对象
            stmt = prepareStatement(handler, ms.getStatementLog());
            // 执行 StatementHandler  ,进行读操作,到这一步的时候已经将查询任务交给StatementHandler了
            return handler.query(stmt, resultHandler);
        } finally {
            // 关闭 StatementHandler 对象
            closeStatement(stmt);
        }
    }
    
  4. 点击prepareStatement
    // 初始化 StatementHandler 对象
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Statement stmt;
        // 获得 Connection 对象
        Connection connection = getConnection(statementLog);
        // 创建 Statement 或 PrepareStatement 预编译对象
        stmt = handler.prepare(connection, transaction.getTimeout());
        // 设置 SQL 上的参数,例如 PrepareStatement 对象上的占位符
        handler.parameterize(stmt);
        //最终将预编译对象进行返回
        return stmt;
    }
    

Mybatis架构原理之StatementHandler

1.StatementHandler主要完成两步

  1. 总结就是参数的传递和结果集的转化
    在这里插入图片描述

  2. SimpleExecutor实现类中的doQuery方法中

    1. 在执行return handler.query(stmt, resultHandler);这一步操作(进行读操作)之前的一行代码stmt = prepareStatement(handler, ms.getStatementLog());,执行了prepareStatement方法,这个方法中的handler.parameterize(stmt);这一步进行了参数设置
  3. 点击parameterize方法,进入PreparedStatementHandlerparameterize方法中

    @Override
    public void parameterize(Statement statement) throws SQLException {
        //使用ParameterHandler对象来完成对Statement的设值,所以说真正设置参数的还是parameterHandler对象
        parameterHandler.setParameters((PreparedStatement) statement);
    }
    
  4. 点击setParameters方法,进入到实现类中,同时也说明了ParametorHandler在设置参数的时候还要调用TypeHandlerTypeHandler设置了Java的类型和jdbc的数据类型转换,在代码的最后TypeHandler也设置了?占位符的参数

    @SuppressWarnings("Duplicates")
    @Override
    public void setParameters(PreparedStatement ps) {
        ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
        // 遍历 ParameterMapping 数组
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings != null) {
            for (int i = 0; i < parameterMappings.size(); i++) {
                // 获得 ParameterMapping 对象
                ParameterMapping parameterMapping = parameterMappings.get(i);
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    // 获得值
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
                        value = boundSql.getAdditionalParameter(propertyName);
                    } else if (parameterObject == null) {
                        value = null;
                    } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                        value = parameterObject;
                    } else {
                        MetaObject metaObject = configuration.newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }
                    // 获得 typeHandler、jdbcType 属性
                    TypeHandler typeHandler = parameterMapping.getTypeHandler();
                    JdbcType jdbcType = parameterMapping.getJdbcType();
                    if (value == null && jdbcType == null) {
                        jdbcType = configuration.getJdbcTypeForNull();
                    }
                    // 设置 ? 占位符的参数
                    try {
                        typeHandler.setParameter(ps, i + 1, value, jdbcType);
                    } catch (TypeException | SQLException e) {
                        throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
                    }
                }
            }
        }
    }
    
  5. 设置参数结束之后可以继续回到SimpleExecutor中的doQuery方法

    1. 上一步结束了参数的设置,接下来就要进行真正的读操作了,执行return handler.query(stmt, resultHandler);这一步了
    2. 点击query方法,找到实现类PreparedStatementHandler中的query方法
      @Override
          public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
              PreparedStatement ps = (PreparedStatement) statement;
              // 执行查询
              ps.execute();
              // 处理返回结果
              return resultSetHandler.handleResultSets(ps);
          }
      
    3. 查看handleResultSet中的handleResultSets是怎么执行的,点击handleResultSets,找到实现类
      //
          // HANDLE RESULT SETS
          //
          // 处理 {@link java.sql.ResultSet} 结果集
          @Override
          public List<Object> handleResultSets(Statement stmt) throws SQLException {
              ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
      
              // 多 ResultSet 的结果集合,每个 ResultSet 对应一个 Object 对象。而实际上,每个 Object 是 List<Object> 对象。
              // 在不考虑存储过程的多 ResultSet 的情况,普通的查询,实际就一个 ResultSet ,也就是说,multipleResults 最多就一个元素。
              final List<Object> multipleResults = new ArrayList<>();
      
              int resultSetCount = 0;
              // 获得首个 ResultSet 对象,并封装成 ResultSetWrapper 对象
              ResultSetWrapper rsw = getFirstResultSet(stmt);
      
              // 获得 ResultMap 数组
              // 在不考虑存储过程的多 ResultSet 的情况,普通的查询,实际就一个 ResultSet ,也就是说,resultMaps 就一个元素。
              List<ResultMap> resultMaps = mappedStatement.getResultMaps();
              int resultMapCount = resultMaps.size();
              validateResultMapsCount(rsw, resultMapCount); // 校验
              while (rsw != null && resultMapCount > resultSetCount) {
                  // 获得 ResultMap 对象
                  ResultMap resultMap = resultMaps.get(resultSetCount);
                  // 处理 ResultSet ,将结果添加到 multipleResults 中
                  handleResultSet(rsw, resultMap, multipleResults, null);
                  // 获得下一个 ResultSet 对象,并封装成 ResultSetWrapper 对象
                  rsw = getNextResultSet(stmt);
                  // 清理
                  cleanUpAfterHandlingResultSet();
                  // resultSetCount ++
                  resultSetCount++;
              }
      
              // 因为 `mappedStatement.resultSets` 只在存储过程中使用,本系列暂时不考虑,忽略即可
              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++;
                  }
              }
      
              // 如果是 multipleResults 单元素,则取首元素返回
              return collapseSingleResultList(multipleResults);
          }
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值