• Mybatis架构相关的知识


    img

    如上所示,这是一个简单的Mybaits执行流程.

    我们其实可以看到,一直到第三步(Sqlsession)那么一步,这都是我们的程序里需要创建的.而之后的步骤才是底层完成的任务.

    • 这里就有了一个引申的概念,四大对象。

      1 executor 调用StatementHandler,以此来执行SQL语句。

      img

      这个是结构图.

      BaseExecutor:这个执行器执行了最基本的功能,其实如果你用debug就能发现。其余几个执行器执行时,也会调用这个 BaseExecutor中的方法。

      SimpleExecutor:最简单的执行器,根据对应的sql直接执行即可,不会做一些额外的操作;拼接完SQL之后,直接交给 StatementHandler 去执行。

      BatchExecutor:通过批量操作来优化性能。通常需要注意的是批量更新操作,由于内部有缓存的实现,使用完成后记得调用flushStatements来清除缓存。

      ReuseExecutor :可重用的执行器,重用的对象是Statement,也就是说该执行器会缓存同一个sql的Statement,省去Statement的重新创建,优化性能。

        内部的实现是通过一个HashMap来维护Statement对象的。由于当前Map只在该session中有效,所以使用完成后记得调用flushStatements来清除Map。

      CachingExecutor:启用于二级缓存时的执行器;

        采用静态代理;代理一个 Executor 对象。

        执行 update 方法前判断是否清空二级缓存;

        执行 query 方法前先在二级缓存中查询,命中失败再通过被代理类查询。

      image-20200620085028706

      它使用StaementHandler实现JDBC的操作的。

      2 parameterHandler:

      这个主要是对参数进行操作。

      public void setParameters(PreparedStatement ps) throws SQLException {
        ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
        //获取一个SQL语句集合的参数列表
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
      //如果参数列表不为空
        if (parameterMappings != null) 
        {
                //循环整个参数列表
          for (int i = 0; i < parameterMappings.size(); i++) {
                  //取出每一个参数
            ParameterMapping parameterMapping = parameterMappings.get(i);
            //??????
            if (parameterMapping.getMode() != ParameterMode.OUT) {
                    //
              Object value;
              //`获取javaBean中的属性名称(如果你用javaBean作为参数输入到SQL语句中,SQL不也是会为你分配到相应的sql中嘛。
              //这个就是)
              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。这是一种可以用来对输入的值进行处理的函数,将java数据类型转化为数据库数据类型。
              //你既可以自己定义,Mybatis也为你提供了一些基本的。
              TypeHandler typeHandler = parameterMapping.getTypeHandler();
              //jdbcType是对应的sql参数(这个是你在XML文件中设置的,用来对应javaType和jdbcType)JDBCtYPE是一个枚举类型
              //  <result property="FLD_NUMBER" column="FLD_NUMBER"  javaType="double" jdbcType="NUMERIC"/>
              JdbcType jdbcType = parameterMapping.getJdbcType();
              //如果两者都为空
              if (value == null && jdbcType == null) jdbcType = configuration.getJdbcTypeForNull();
                 //
              typeHandler.setParameter(ps, i + 1, value, jdbcType);
            }
          }
        }
      }
      //设置参数
      public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
             如果参数列表为空
              if (parameter == null) {
                      对应的jdbcType为空
                if (jdbcType == null) {
                        可以为空的参数必须设置jdbcType,否则就报错。
                  throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
                }
                try {
                  ps.setNull(i, jdbcType.TYPE_CODE);
                } catch (SQLException e) {
                  throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
                                  "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
                                  "Cause: " + e, e);
                }
              } else {
                      //根据传入参数的不同,调用不同种类的set函数,让其进行替换。
                setNonNullParameter(ps, i, parameter, jdbcType);
              }
            }
      

      3 ResultSetHandler

      对结果进行操作,将SQL的查询加入到java类型之中。

      img

      public interface ResultSetHandler {
          // 将Statement执行后产生的结果集(可能有多个结果集)映射为结果列表
        <E> List<E> handleResultSets(Statement stmt) throws SQLException;
      
        <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
          // 处理存储过程执行后的输出参数
        void handleOutputParameters(CallableStatement cs) throws SQLException;
      
      }
      

      3. DefaultResultSetHandler

        ResultSetHandler的具体实现类是DefaultResultSetHandler,其实现的步骤就是将Statement执行后的结果集,按照Mapper文件中配置的ResultType或ResultMap来封装成对应的对象,最后将封装的对象返回 。

        以最常用的 handleResultSets 为例进行简单的分析:

      public List<Object> handleResultSets(Statement stmt) throws SQLException {
          ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
      
          final List<Object> multipleResults = new ArrayList<Object>();
      
          int resultSetCount = 0;
          // 第一个结果集
          ResultSetWrapper rsw = getFirstResultSet(stmt);
          // 获取 resultMap 
          List<ResultMap> resultMaps = mappedStatement.getResultMaps();
          int resultMapCount = resultMaps.size();
          // 判断 ResultMap 是否为空,空则抛异常
          validateResultMapsCount(rsw, resultMapCount);
          // 处理第一个结果集
          while (rsw != null && resultMapCount > resultSetCount) {
            ResultMap resultMap = resultMaps.get(resultSetCount);
            // 将结果集映射为对应的 ResultMap 对象
            handleResultSet(rsw, resultMap, multipleResults, null);
            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);
        }
      

      4 StatementHandler:
      这个参数操作了SQL语句的整个执行流程。

    image-20200620104032120

    这个我以前有文章进行过讲解,所以这个就先算了。就不讲了。


    既然对于四大接口(四大对象)有了基本的了解。那么我们就看看下面的图片。我想应该不算很难吧。

    img

    参数映射部分算是对应:parameterHandler:

    XML配置加载部分可以看看如下这张图片:

    img

    参数映射部分在这篇文章中

    之后是SQL语句执行:

    这个步骤在我看来是对应StatementHandler

    结果映射则是由ResultSetHandler完成的.

    (当然,这个就是理解一下四大对象在Mybatis中发生什么作用)


    各种常用的Mybatis主要作用。

    • BoundSql类,封装mybatis最终产生sql的类,包括sql语句,参数,参数源数据等参数:
    • Configuration类:就像是MyBatis的总管,里面包含了所有的信息。无论是连接
  • 相关阅读:
    koa学习中的一系列问题-mongodb
    JS基础语法使用
    vue中的this指向问题
    CDN的问题
    vue基本语法及使用
    python自动化读取excel数据,写入excel数据,xlrd、xlutils
    jenkins配置邮件发送功能
    pytest生成的index.html报告发送邮箱后没有样式的解决办法
    pytest命令同时执行多个目录,多个不同目录下的文件
    pytest+jenkins+allure生成报告
  • 原文地址:https://www.cnblogs.com/yanzezhong/p/13233901.html
Copyright © 2020-2023  润新知