zoukankan      html  css  js  c++  java
  • Mybatis之工作原理

    1.Mybatis的架构

    1.1 Mybatis的框架分层

    这里写图片描述

    1.2 MyBatis的实现原理

    mybatis底层还是采用原生jdbc来对数据库进行操作的,它支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架,其主要就完成2件事情:

    1. 封装JDBC操作
    2. 利用反射打通Java类与SQL语句之间的相互转换

    MyBatis的主要设计目的就是让我们对执行SQL语句时对输入输出的数据管理更加方便,所以方便地写出SQL和方便地获取SQL的执行结果才是MyBatis的核心竞争力。

    它通过SqlSessionFactory,SqlSession,Executor,StatementHandler,ParameterHandler,ResultHandler和TypeHandler等几个处理器封装了这些过程

    执行器:Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed),是MyBatis调度的核心,负责SQL语句的生成和查询缓存的维护
    参数处理器:ParameterHandler(getParameterObject, setParameters),负责对用户传递的参数转换成JDBC Statement所对应的数据类型
    结构处理器:ResultSetHandler(handleResultSets, handleOutputParameters),负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
    sql查询处理器:StatementHandler(prepare, parameterize, batch, update, query),封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数等
    Configuration:MyBatis所有的配置信息都保存在Configuration对象之中,配置文件中的大部分配置都会存储到该类中
    SqlSession:作为MyBatis工作的主要顶层API,表示和数据库交互时的会话,完成必要数据库增删改查功能
    TypeHandler:负责java数据类型和jdbc数据类型(也可以说是数据表列类型)之间的映射和转换
    MappedStatement:MappedStatement维护一条<select|update|delete|insert>节点的封装
    SqlSource:负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
    BoundSql:表示动态生成的SQL语句以及相应的参数信
    BaseBuilder:负责解析xml映射文件,生成sql语句,包括解析select|insert|update|delete|cache-ref|cache|resultMap|sql|parameterMap|namespace|where|trim|set|where|if|foreach|choose|if|when|otherwise|bind|parameterType|resultType|resultMap,该类是抽象类,它有很多子类。

    其中StatementHandler用通过ParameterHandler与ResultHandler分别进行参数预编译 与结果处理。而ParameterHandler与ResultHandler都使用TypeHandler进行映射。

    BaseBuilder的类图继承结构如下:

    如下图: 

    2.Mybatis工作过程

    通过读mybatis的源码进行分析mybatis的执行操作的整个过程,我们通过debug调试就可以知道Mybatis每一步做了什么事,我先把debug每一步结果 截图,然后在分析这个流程。 
    第一步:读取配置文件,形成InputStream:

    String resource = "mybatis.xml";
    
    // 加载mybatis的配置文件(它也加载关联的映射文件)
    InputStream inputStream = null;
    try {
        inputStream = Resources.getResourceAsStream(resource);
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    // 构建sqlSession的工厂
    sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    2.1 解析xml文件并创建SqlSessionFacotry的过程

    首先会创建SqlSessionFactoryBuilder对象,然后由它进行创建SqlSessionFactory。这里用到的是建造者模式,建造者模式最简单的理解就是不手动new对象,而是由其他类来进行对象的创建。

    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        try {
          XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
          return build(parser.parse());
        } catch (Exception e) {
          throw ExceptionFactory.wrapException("Error building SqlSession.", e);
        } finally {
          ErrorContext.instance().reset();
          try {
            inputStream.close();
          } catch (IOException e) {
            // Intentionally ignore. Prefer previous error.
          }
        }
      }
        
      public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
      }

    XMLConfigBuilder对象会进行XML配置文件的解析,实际为configuration节点的解析操作。

    // XMLConfigBuilder类
    public Configuration parse() {
        if (parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        }
        parsed = true;
        parseConfiguration(parser.evalNode("/configuration"));
        return configuration;
    }
    
    private void parseConfiguration(XNode root) {
        try {
            //issue #117 read properties first
            propertiesElement(root.evalNode("properties"));
            Properties settings = settingsAsProperties(root.evalNode("settings"));
            loadCustomVfs(settings);
            typeAliasesElement(root.evalNode("typeAliases"));
            pluginElement(root.evalNode("plugins"));
            objectFactoryElement(root.evalNode("objectFactory"));
            objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
            reflectorFactoryElement(root.evalNode("reflectorFactory"));
            settingsElement(settings);
            // read it after objectFactory and objectWrapperFactory issue #631
    
            /* 处理environments节点数据 */
            environmentsElement(root.evalNode("environments"));
            databaseIdProviderElement(root.evalNode("databaseIdProvider"));
            typeHandlerElement(root.evalNode("typeHandlers"));
            mapperElement(root.evalNode("mappers"));
        } catch (Exception e) {
            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
        }
    }

    在configuration节点下会依次解析properties/settings/.../mappers等节点配置。在解析environments节点时,会根据transactionManager的配置来创建事务管理器,根据dataSource的配置来创建DataSource对象,这里面包含了数据库登录的相关信息。在解析mappers节点时,会读取该节点下所有的mapper文件,然后进行解析,并将解析后的结果存到configuration对象中。

    // XMLConfigBuilder类
    private void environmentsElement(XNode context) throws Exception {
        if (context != null) {
            if (environment == null) {
                environment = context.getStringAttribute("default");
            }
            for (XNode child : context.getChildren()) {
                String id = child.getStringAttribute("id");
                if (isSpecifiedEnvironment(id)) {
    
                    /* 创建事务管理器 */
                    TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
                    DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
                    DataSource dataSource = dsFactory.getDataSource();
    
                    /* 建造者模式 设计模式 */
                    Environment.Builder environmentBuilder = new Environment.Builder(id)
                            .transactionFactory(txFactory)
                            .dataSource(dataSource);
                    configuration.setEnvironment(environmentBuilder.build());
                }
            }
        }
    }
    
    // 解析单独的mapper文件
    private void mapperElement(XNode parent) throws Exception {
        if (parent != null) {
          for (XNode child : parent.getChildren()) {
            if ("package".equals(child.getName())) {
              String mapperPackage = child.getStringAttribute("name");
              configuration.addMappers(mapperPackage);
            } else {
              String resource = child.getStringAttribute("resource");
              String url = child.getStringAttribute("url");
              String mapperClass = child.getStringAttribute("class");
              if (resource != null && url == null && mapperClass == null) {
                ErrorContext.instance().resource(resource);
                InputStream inputStream = Resources.getResourceAsStream(resource);
                XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
                mapperParser.parse(); // 开始解析mapper文件了 :)
              } else if (resource == null && url != null && mapperClass == null) {
                ErrorContext.instance().resource(url);
                InputStream inputStream = Resources.getUrlAsStream(url);
                XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
                mapperParser.parse();
              } else if (resource == null && url == null && mapperClass != null) {
                Class<?> mapperInterface = Resources.classForName(mapperClass);
                configuration.addMapper(mapperInterface);
              } else {
                throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
              }
            }
          }
        }
      }

    使用类XMLMapperBuilder解析每个mapper的xml文件

    public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
        this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
            configuration, resource, sqlFragments);
      }
    
      private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
        super(configuration);
        this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
        this.parser = parser;
        this.sqlFragments = sqlFragments;
        this.resource = resource;
      }
    
      public void parse() {
        if (!configuration.isResourceLoaded(resource)) {
          configurationElement(parser.evalNode("/mapper"));
          configuration.addLoadedResource(resource);
          bindMapperForNamespace();
        }
    
        parsePendingResultMaps();
        parsePendingCacheRefs();
        parsePendingStatements();
      }
    
      public XNode getSqlFragment(String refid) {
        return sqlFragments.get(refid);
      }
    
      private void configurationElement(XNode context) {
        try {
          String namespace = context.getStringAttribute("namespace");
          if (namespace == null || namespace.equals("")) {
            throw new BuilderException("Mapper's namespace cannot be empty");
          }
          builderAssistant.setCurrentNamespace(namespace);
          cacheRefElement(context.evalNode("cache-ref"));
          cacheElement(context.evalNode("cache"));
          parameterMapElement(context.evalNodes("/mapper/parameterMap"));
          resultMapElements(context.evalNodes("/mapper/resultMap"));
          sqlElement(context.evalNodes("/mapper/sql"));
          buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
        } catch (Exception e) {
          throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
        }
      }
    
      private void buildStatementFromContext(List<XNode> list) {
        if (configuration.getDatabaseId() != null) {
          buildStatementFromContext(list, configuration.getDatabaseId());
        }
        buildStatementFromContext(list, null);
      }
    
      private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
        for (XNode context : list) {
          final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
          try {
            statementParser.parseStatementNode();
          } catch (IncompleteElementException e) {
            configuration.addIncompleteStatement(statementParser);
          }
        }
      }
    
      private void parsePendingResultMaps() {
        Collection<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps();
        synchronized (incompleteResultMaps) {
          Iterator<ResultMapResolver> iter = incompleteResultMaps.iterator();
          while (iter.hasNext()) {
            try {
              iter.next().resolve();
              iter.remove();
            } catch (IncompleteElementException e) {
              // ResultMap is still missing a resource...
            }
          }
        }
      }
    
      private void parsePendingCacheRefs() {
        Collection<CacheRefResolver> incompleteCacheRefs = configuration.getIncompleteCacheRefs();
        synchronized (incompleteCacheRefs) {
          Iterator<CacheRefResolver> iter = incompleteCacheRefs.iterator();
          while (iter.hasNext()) {
            try {
              iter.next().resolveCacheRef();
              iter.remove();
            } catch (IncompleteElementException e) {
              // Cache ref is still missing a resource...
            }
          }
        }
      }
    
      private void parsePendingStatements() {
        Collection<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements();
        synchronized (incompleteStatements) {
          Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator();
          while (iter.hasNext()) {
            try {
              iter.next().parseStatementNode();
              iter.remove();
            } catch (IncompleteElementException e) {
              // Statement is still missing a resource...
            }
          }
        }
      }
    
      private void cacheRefElement(XNode context) {
        if (context != null) {
          configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
          CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
          try {
            cacheRefResolver.resolveCacheRef();
          } catch (IncompleteElementException e) {
            configuration.addIncompleteCacheRef(cacheRefResolver);
          }
        }
      }
    
      private void cacheElement(XNode context) throws Exception {
        if (context != null) {
          String type = context.getStringAttribute("type", "PERPETUAL");
          Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
          String eviction = context.getStringAttribute("eviction", "LRU");
          Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
          Long flushInterval = context.getLongAttribute("flushInterval");
          Integer size = context.getIntAttribute("size");
          boolean readWrite = !context.getBooleanAttribute("readOnly", false);
          boolean blocking = context.getBooleanAttribute("blocking", false);
          Properties props = context.getChildrenAsProperties();
          builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
        }
      }
    
      private void parameterMapElement(List<XNode> list) throws Exception {
        for (XNode parameterMapNode : list) {
          String id = parameterMapNode.getStringAttribute("id");
          String type = parameterMapNode.getStringAttribute("type");
          Class<?> parameterClass = resolveClass(type);
          List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
          List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
          for (XNode parameterNode : parameterNodes) {
            String property = parameterNode.getStringAttribute("property");
            String javaType = parameterNode.getStringAttribute("javaType");
            String jdbcType = parameterNode.getStringAttribute("jdbcType");
            String resultMap = parameterNode.getStringAttribute("resultMap");
            String mode = parameterNode.getStringAttribute("mode");
            String typeHandler = parameterNode.getStringAttribute("typeHandler");
            Integer numericScale = parameterNode.getIntAttribute("numericScale");
            ParameterMode modeEnum = resolveParameterMode(mode);
            Class<?> javaTypeClass = resolveClass(javaType);
            JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
            @SuppressWarnings("unchecked")
            Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
            ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
            parameterMappings.add(parameterMapping);
          }
          builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
        }
      }
    
      private void resultMapElements(List<XNode> list) throws Exception {
        for (XNode resultMapNode : list) {
          try {
            resultMapElement(resultMapNode);
          } catch (IncompleteElementException e) {
            // ignore, it will be retried
          }
        }
      }
    
      private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
        return resultMapElement(resultMapNode, Collections.<ResultMapping> emptyList());
      }
    
      private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception {
        ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
        String id = resultMapNode.getStringAttribute("id",
            resultMapNode.getValueBasedIdentifier());
        String type = resultMapNode.getStringAttribute("type",
            resultMapNode.getStringAttribute("ofType",
                resultMapNode.getStringAttribute("resultType",
                    resultMapNode.getStringAttribute("javaType"))));
        String extend = resultMapNode.getStringAttribute("extends");
        Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
        Class<?> typeClass = resolveClass(type);
        Discriminator discriminator = null;
        List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
        resultMappings.addAll(additionalResultMappings);
        List<XNode> resultChildren = resultMapNode.getChildren();
        for (XNode resultChild : resultChildren) {
          if ("constructor".equals(resultChild.getName())) {
            processConstructorElement(resultChild, typeClass, resultMappings);
          } else if ("discriminator".equals(resultChild.getName())) {
            discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
          } else {
            List<ResultFlag> flags = new ArrayList<ResultFlag>();
            if ("id".equals(resultChild.getName())) {
              flags.add(ResultFlag.ID);
            }
            resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
          }
        }
        ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
        try {
          return resultMapResolver.resolve();
        } catch (IncompleteElementException  e) {
          configuration.addIncompleteResultMap(resultMapResolver);
          throw e;
        }
      }
    
      private void processConstructorElement(XNode resultChild, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
        List<XNode> argChildren = resultChild.getChildren();
        for (XNode argChild : argChildren) {
          List<ResultFlag> flags = new ArrayList<ResultFlag>();
          flags.add(ResultFlag.CONSTRUCTOR);
          if ("idArg".equals(argChild.getName())) {
            flags.add(ResultFlag.ID);
          }
          resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags));
        }
      }
    
      private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
        String column = context.getStringAttribute("column");
        String javaType = context.getStringAttribute("javaType");
        String jdbcType = context.getStringAttribute("jdbcType");
        String typeHandler = context.getStringAttribute("typeHandler");
        Class<?> javaTypeClass = resolveClass(javaType);
        @SuppressWarnings("unchecked")
        Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
        JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
        Map<String, String> discriminatorMap = new HashMap<String, String>();
        for (XNode caseChild : context.getChildren()) {
          String value = caseChild.getStringAttribute("value");
          String resultMap = caseChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings));
          discriminatorMap.put(value, resultMap);
        }
        return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);
      }
    
      private void sqlElement(List<XNode> list) throws Exception {
        if (configuration.getDatabaseId() != null) {
          sqlElement(list, configuration.getDatabaseId());
        }
        sqlElement(list, null);
      }
    
      private void sqlElement(List<XNode> list, String requiredDatabaseId) throws Exception {
        for (XNode context : list) {
          String databaseId = context.getStringAttribute("databaseId");
          String id = context.getStringAttribute("id");
          id = builderAssistant.applyCurrentNamespace(id, false);
          if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
            sqlFragments.put(id, context);
          }
        }
      }
      
      private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
        if (requiredDatabaseId != null) {
          if (!requiredDatabaseId.equals(databaseId)) {
            return false;
          }
        } else {
          if (databaseId != null) {
            return false;
          }
          // skip this fragment if there is a previous one with a not null databaseId
          if (this.sqlFragments.containsKey(id)) {
            XNode context = this.sqlFragments.get(id);
            if (context.getStringAttribute("databaseId") != null) {
              return false;
            }
          }
        }
        return true;
      }
    
      private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) throws Exception {
        String property;
        if (flags.contains(ResultFlag.CONSTRUCTOR)) {
          property = context.getStringAttribute("name");
        } else {
          property = context.getStringAttribute("property");
        }
        String column = context.getStringAttribute("column");
        String javaType = context.getStringAttribute("javaType");
        String jdbcType = context.getStringAttribute("jdbcType");
        String nestedSelect = context.getStringAttribute("select");
        String nestedResultMap = context.getStringAttribute("resultMap",
            processNestedResultMappings(context, Collections.<ResultMapping> emptyList()));
        String notNullColumn = context.getStringAttribute("notNullColumn");
        String columnPrefix = context.getStringAttribute("columnPrefix");
        String typeHandler = context.getStringAttribute("typeHandler");
        String resultSet = context.getStringAttribute("resultSet");
        String foreignColumn = context.getStringAttribute("foreignColumn");
        boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));
        Class<?> javaTypeClass = resolveClass(javaType);
        @SuppressWarnings("unchecked")
        Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
        JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
        return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy);
      }
      
      private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings) throws Exception {
        if ("association".equals(context.getName())
            || "collection".equals(context.getName())
            || "case".equals(context.getName())) {
          if (context.getStringAttribute("select") == null) {
            ResultMap resultMap = resultMapElement(context, resultMappings);
            return resultMap.getId();
          }
        }
        return null;
      }
    
      private void bindMapperForNamespace() {
        String namespace = builderAssistant.getCurrentNamespace();
        if (namespace != null) {
          Class<?> boundType = null;
          try {
            boundType = Resources.classForName(namespace);
          } catch (ClassNotFoundException e) {
            //ignore, bound type is not required
          }
          if (boundType != null) {
            if (!configuration.hasMapper(boundType)) {
              // Spring may not know the real resource name so we set a flag
              // to prevent loading again this resource from the mapper interface
              // look at MapperAnnotationBuilder#loadXmlResource
              configuration.addLoadedResource("namespace:" + namespace);
              configuration.addMapper(boundType);
            }
          }
        }
      }

    解析玩xml文件之后,使用类XMLStatementBuilder创建每个sql(包括insert,update,select,delete等)语句的MappedStatement。

    public void parseStatementNode() {
        String id = context.getStringAttribute("id");
        String databaseId = context.getStringAttribute("databaseId");
    
        if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
          return;
        }
    
        Integer fetchSize = context.getIntAttribute("fetchSize");
        Integer timeout = context.getIntAttribute("timeout");
        String parameterMap = context.getStringAttribute("parameterMap");
        String parameterType = context.getStringAttribute("parameterType");
        Class<?> parameterTypeClass = resolveClass(parameterType);
        String resultMap = context.getStringAttribute("resultMap");
        String resultType = context.getStringAttribute("resultType");
        String lang = context.getStringAttribute("lang");
        LanguageDriver langDriver = getLanguageDriver(lang);
    
        Class<?> resultTypeClass = resolveClass(resultType);
        String resultSetType = context.getStringAttribute("resultSetType");
        StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
        ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
    
        String nodeName = context.getNode().getNodeName();
        SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
        boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
        boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
        boolean useCache = context.getBooleanAttribute("useCache", isSelect);
        boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
    
        // Include Fragments before parsing
        XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
        includeParser.applyIncludes(context.getNode());
    
        // Parse selectKey after includes and remove them.
        processSelectKeyNodes(id, parameterTypeClass, langDriver);
        
        // Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
        SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
        String resultSets = context.getStringAttribute("resultSets");
        String keyProperty = context.getStringAttribute("keyProperty");
        String keyColumn = context.getStringAttribute("keyColumn");
        KeyGenerator keyGenerator;
        String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
        keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
        if (configuration.hasKeyGenerator(keyStatementId)) {
          keyGenerator = configuration.getKeyGenerator(keyStatementId);
        } else {
          keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
              configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
              ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
        }
    
        builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
            fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
            resultSetTypeEnum, flushCache, useCache, resultOrdered, 
            keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
      }

    解析完MyBatis配置文件后,configuration就初始化完成了,然后根据configuration对象来创建SqlSessionFactory,到这里时,MyBatis的初始化的征程已经走完了。

    // SqlSessionFactoryBuilder类
    public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
    }

    这里写图片描述
    从debug调试看出 返回的 sqlSessionFactory 是DefaultSesssionFactory类型的,但是configuration此时已经被初始化了。查看源码后画如下创建DefaultSessionFactory的时序图: 
    这里写图片描述

    2.2 创建SqlSession的过程

    这里写图片描述 
    从debug调试看出SqlSessinoFactory.openSession() 返回的sqlSession是DefaultSession类型的,此SqlSession里包含一个Configuration的对象,和一个Executor对象。查看源码后画如下创建DefaultSession的时序图:

    这里写图片描述

    2.3 创建Mapper的过程

    这里写图片描述
    从debug调试可以看出,mapper是一个Mapper代理对象,而且初始化了Configuration对象,Executor的对象。查看源码后画如下创建Mapper的时序图: 
    这里写图片描述

    2.4 执行CRUD过程

    2.4.1 以select为例查看各步执行的源码

    1.mapper.selectEmployeeList()实现原理其实用的jdk动态代理,调试代码发现:

    首先是MapperFactoryBean:

    /**
       * {@inheritDoc}
       */
      @Override
      public T getObject() throws Exception {
        return getSqlSession().getMapper(this.mapperInterface);
      }

    SqlSessionDaoSupport:它得到的是SqlSessionTemplate类,它是接口SqlSession的实现类。

    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        if (!this.externalSqlSession) {
          this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
        }
      }
    
      public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSession = sqlSessionTemplate;
        this.externalSqlSession = true;
      }
    
      /**
       * Users should use this method to get a SqlSession to call its statement methods
       * This is SqlSession is managed by spring. Users should not commit/rollback/close it
       * because it will be automatically done.
       *
       * @return Spring managed thread safe SqlSession
       */
      public SqlSession getSqlSession() {
        return this.sqlSession;
      }

    SqlSessionTemplate:

    /**
       * {@inheritDoc}
       */
      @Override
      public <T> T getMapper(Class<T> type) {
        return getConfiguration().getMapper(type, this);
      }

    SqlSessionTemplate:

    @Override
      public Configuration getConfiguration() {
        return this.sqlSessionFactory.getConfiguration();
      }

    DefaultSqlSessionFactory:

    @Override
      public Configuration getConfiguration() {
        return configuration;
      }

    然后是Configuration:

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
     return this.mapperRegistry.getMapper(type, sqlSession);
     }

    最后是MapperRegistry:

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
     MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
     if(mapperProxyFactory == null) {
     throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
     } else {
     try {
     return mapperProxyFactory.newInstance(sqlSession);
     } catch (Exception var5) {
     throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
     }
     }
     }

    该方法中最关键代码:mapperProxyFactory.newInstance(sqlSession);

    MapperProxyFactory是一个创建MapperProxy的工厂类,调用其中的newInstance方法可以获取到一个代理对象,继续往下看

    MapperProxyFactory:

    protected T newInstance(MapperProxy<T> mapperProxy) {
     return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
     }
     public T newInstance(SqlSession sqlSession) {
     MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
     return this.newInstance(mapperProxy);
     }

    在该类中可以看到, Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);

    最终由JDK的动态代理,动态的为我们在内存中创建了一个代理对象。到此,我们已经看到了一部分真相,就是我们为mybatis提供Mapper接口,而mybatis使用JDK的动态代理为我们生成实现类。

    下面就是InvocationHandler的实现,从上面的代码中可以看到,它叫做MapperProxy

    MapperProxy:

    public class MapperProxy<T> implements InvocationHandler, Serializable {
     private static final long serialVersionUID = -6424540398559729838L;
     private final SqlSession sqlSession;
     private final Class<T> mapperInterface;
     private final Map<Method, MapperMethod> methodCache;
     public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
     this.sqlSession = sqlSession;
     this.mapperInterface = mapperInterface;
     this.methodCache = methodCache;
     }
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     if(Object.class.equals(method.getDeclaringClass())) {
     return method.invoke(this, args);
     } else {
     MapperMethod mapperMethod = this.cachedMapperMethod(method);
     return mapperMethod.execute(this.sqlSession, args);
     }
     }
     private MapperMethod cachedMapperMethod(Method method) {
     MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
     if(mapperMethod == null) {
     mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
     this.methodCache.put(method, mapperMethod);
     }
     return mapperMethod;
     }
    }

    在invoke方法中可以看到,如果我们调用的是Object中的方法,不做任何处理,直接调用,否则执行:mapperMethod.execute(this.sqlSession, args)。

    MapperMethod:经过上面的调用后进入MapperMethod里面执行

    //判断sql命令类型
    public Object execute(SqlSession sqlSession, Object[] args) {
            Object param;
            Object result;
            if(SqlCommandType.INSERT == this.command.getType()) {
                param = this.method.convertArgsToSqlCommandParam(args);
                result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
            } else if(SqlCommandType.UPDATE == this.command.getType()) {
                param = this.method.convertArgsToSqlCommandParam(args);
                result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
            } else if(SqlCommandType.DELETE == this.command.getType()) {
                param = this.method.convertArgsToSqlCommandParam(args);
                result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
            } else if(SqlCommandType.SELECT == this.command.getType()) {
            //我们测试的是select类型,则再判断这个方法的返回类型
                if(this.method.returnsVoid() && this.method.hasResultHandler()) {
                    this.executeWithResultHandler(sqlSession, args);
                    result = null;
                } else if(this.method.returnsMany()) {
                   //我们是查询列表,此方法执行
                    result = this.executeForMany(sqlSession, args);
                } else if(this.method.returnsMap()) {
                    result = this.executeForMap(sqlSession, args);
                } else {
                    param = this.method.convertArgsToSqlCommandParam(args);
                    result = sqlSession.selectOne(this.command.getName(), param);
                }
            } else {
                if(SqlCommandType.FLUSH != this.command.getType()) {
                    throw new BindingException("Unknown execution method for: " + this.command.getName());
                }
    
                result = sqlSession.flushStatements();
            }
    
            if(result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
                throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
            } else {
                return result;
            }
        }
    
    private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    //将param做处理 自动处理为param1,param2..
            Object param = this.method.convertArgsToSqlCommandParam(args);
            List result;
            if(this.method.hasRowBounds()) {
                RowBounds rowBounds = this.method.extractRowBounds(args);
                //调用该对象的DefaultSqlSession的selectList方法
                result = sqlSession.selectList(this.command.getName(), param, rowBounds);
            } else {
                result = sqlSession.selectList(this.command.getName(), param);
            }
    
            return !this.method.getReturnType().isAssignableFrom(result.getClass())?(this.method.getReturnType().isArray()?this.convertToArray(result):this.convertToDeclaredCollection(sqlSession.getConfiguration(), result)):result;
        }
    
    //处理参数方法
     public Object convertArgsToSqlCommandParam(Object[] args) {
                int paramCount = this.params.size();
                if(args != null && paramCount != 0) {
                    if(!this.hasNamedParameters && paramCount == 1) {
                        return args[((Integer)this.params.keySet().iterator().next()).intValue()];
                    } else {
                        Map<String, Object> param = new MapperMethod.ParamMap();
                        int i = 0;
    
                        for(Iterator i$ = this.params.entrySet().iterator(); i$.hasNext(); ++i) {
                            Entry<Integer, String> entry = (Entry)i$.next();
                            param.put(entry.getValue(), args[((Integer)entry.getKey()).intValue()]);
                            String genericParamName = "param" + String.valueOf(i + 1);
                            if(!param.containsKey(genericParamName)) {
                                param.put(genericParamName, args[((Integer)entry.getKey()).intValue()]);
                            }
                        }
    
                        return param;
                    }
                } else {
                    return null;
                }
            }

    主要将SQL分为两类执行,DML和SQL。如果是DML,调用SQLSession中对应的方法执行,并且使用rowCountResult方法根据方法的返回值和受影响的行数做处理。

    如果是查询,则要根据方法的返回值的类型来执行不同的方法。如果Collection系的集合获取数组来接收,使用selectList方法执行查询。如果使用Map集合,调用selectMap方法执行查询。否则,调用selectOne执行查询。

    下面是调用DefaultSqlSession的selectList的方法

    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
            List var5;
            try {
            //获取MappedStatement对象
                MappedStatement ms = this.configuration.getMappedStatement(statement);
                //调用cachingExecutor执行器的方法
                var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
            } catch (Exception var9) {
                throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);
            } finally {
                ErrorContext.instance().reset();
            }
    
            return var5;
        }
    
    //CachingExector的query方法
    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
        //
            BoundSql boundSql = ms.getBoundSql(parameterObject);
            CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);
            //调用下2代码
            return this.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        }
        //2代码
     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) {
                this.flushCacheIfRequired(ms);
                if(ms.isUseCache() && resultHandler == null) {
                    this.ensureNoOutParams(ms, parameterObject, boundSql);
                    List<E> list = (List)this.tcm.getObject(cache, key);
                    if(list == null) {
                    //这里是调用Executor里的query方法 如果开启了缓存这掉CachingExecutor的 如果没有则是调用BaseExecutor的
                        list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                        this.tcm.putObject(cache, key, list);
                    }
    
                    return list;
                }
            }
    
            return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        }

    BaseExecutor的query方法

    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(this.closed) {
                throw new ExecutorException("Executor was closed.");
            } else {
                if(this.queryStack == 0 && ms.isFlushCacheRequired()) {
                    this.clearLocalCache();
                }
    
                List list;
                try {
                    ++this.queryStack;
                    list = resultHandler == null?(List)this.localCache.getObject(key):null;
                    if(list != null) {
                        this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
                    } else {
                    //如果缓存中没有就从数据库中查询
                        list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
                    }
                } finally {
                    --this.queryStack;
                }
    
                if(this.queryStack == 0) {
                    Iterator i$ = this.deferredLoads.iterator();
    
                    while(i$.hasNext()) {
                        BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)i$.next();
                        deferredLoad.load();
                    }
    
                    this.deferredLoads.clear();
                    if(this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
                        this.clearLocalCache();
                    }
                }
    
                return list;
            }
        }
    
    //从数据库中查询
    private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
            //放入缓存
            this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
    
            List list;
            try {
            //此处是调用子Executor的方法,ExecutorType默认是使用的SimpleExecutor
                list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
            } finally {
                this.localCache.removeObject(key);
            }
    
            this.localCache.putObject(key, list);
            if(ms.getStatementType() == StatementType.CALLABLE) {
                this.localOutputParameterCache.putObject(key, parameter);
            }
    
            return list;
        }

    SimpleExecutor的doQuery方法

    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
            Statement stmt = null;
    
            List var9;
            try {
                Configuration configuration = ms.getConfiguration();
                //创建StateMentHandler处理器
                StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
                //调用下3的方法
                stmt = this.prepareStatement(handler, ms.getStatementLog());
                //调用no4的方法
                var9 = handler.query(stmt, resultHandler);
            } finally {
                this.closeStatement(stmt);
            }
    
            return var9;
        }
        //下3方法
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
            Connection connection = this.getConnection(statementLog);
            Statement stmt = handler.prepare(connection);
            //SatementHanlder 采用PreparedStatementHandler来实现此方法,而PreparedStatementHandler调用的是父接口ParameterHandler的方法
            handler.parameterize(stmt);
            return stmt;
        }

    ParameterHandler参数处理器的方法

    public interface ParameterHandler {
        Object getParameterObject();
        //此方法是用DefaultParameterHandler实现的
        void setParameters(PreparedStatement var1) throws SQLException;
    }

    DefaultParameterHandler默认参数处理器的方法

    public void setParameters(PreparedStatement ps) {
            ErrorContext.instance().activity("setting parameters").object(this.mappedStatement.getParameterMap().getId());
            List<ParameterMapping> parameterMappings = this.boundSql.getParameterMappings();
            if(parameterMappings != null) {
                for(int i = 0; i < parameterMappings.size(); ++i) {
                    ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);
                    if(parameterMapping.getMode() != ParameterMode.OUT) {
                        String propertyName = parameterMapping.getProperty();
                        Object value;
                        if(this.boundSql.hasAdditionalParameter(propertyName)) {
                            value = this.boundSql.getAdditionalParameter(propertyName);
                        } else if(this.parameterObject == null) {
                            value = null;
                        } else if(this.typeHandlerRegistry.hasTypeHandler(this.parameterObject.getClass())) {
                            value = this.parameterObject;
                        } else {
                            MetaObject metaObject = this.configuration.newMetaObject(this.parameterObject);
                            value = metaObject.getValue(propertyName);
                        }
                       //这里用调用 TypeHandler类型映射处理器来映射
                        TypeHandler typeHandler = parameterMapping.getTypeHandler();
                        JdbcType jdbcType = parameterMapping.getJdbcType();
                        if(value == null && jdbcType == null) {
                            jdbcType = this.configuration.getJdbcTypeForNull();
                        }
    
                        try {
                        //类型处理器设置参数映射
                                                   typeHandler.setParameter(ps, i + 1, value, jdbcType);
                        } catch (TypeException var10) {
                            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var10, var10);
                        } catch (SQLException var11) {
                            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var11, var11);
                        }
                    }
                }
            }
    
        }

    no4的方法

    public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
           //此处调用原生sql的处理器
            PreparedStatement ps = (PreparedStatement)statement;
            //发出原生sql命令
            ps.execute();
            //采用ResultHandler结果处理器对结果集封装
            return this.resultSetHandler.handleResultSets(ps);
        }

    ResultHandler代码

    public interface ResultSetHandler {
        //此处调用的是DefaultResultSetHandler的方法
        <E> List<E> handleResultSets(Statement var1) throws SQLException;
    
        void handleOutputParameters(CallableStatement var1) throws SQLException;
    }

    DefaultResultSetHandler的方法

    public List<Object> handleResultSets(Statement stmt) throws SQLException {
            ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId());
            List<Object> multipleResults = new ArrayList();
            int resultSetCount = 0;
            ResultSetWrapper rsw = this.getFirstResultSet(stmt);
            List<ResultMap> resultMaps = this.mappedStatement.getResultMaps();
            int resultMapCount = resultMaps.size();
            this.validateResultMapsCount(rsw, resultMapCount);
    
            while(rsw != null && resultMapCount > resultSetCount) {
                ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount);
                this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null);
                rsw = this.getNextResultSet(stmt);
                this.cleanUpAfterHandlingResultSet();
                ++resultSetCount;
            }
    
            String[] resultSets = this.mappedStatement.getResulSets();
            if(resultSets != null) {
                while(rsw != null && resultSetCount < resultSets.length) {
                    ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]);
                    if(parentMapping != null) {
                        String nestedResultMapId = parentMapping.getNestedResultMapId();
                        ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId);
                        this.handleResultSet(rsw, resultMap, (List)null, parentMapping);
                    }
    
                    rsw = this.getNextResultSet(stmt);
                    this.cleanUpAfterHandlingResultSet();
                    ++resultSetCount;
                }
            }
    
            return this.collapseSingleResultList(multipleResults);
        }
    //处理结果集
     private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
            try {
                if(parentMapping != null) {
                    this.handleRowValues(rsw, resultMap, (ResultHandler)null, RowBounds.DEFAULT, parentMapping);
                } else if(this.resultHandler == null) {
                    DefaultResultHandler defaultResultHandler = new DefaultResultHandler(this.objectFactory);
                    this.handleRowValues(rsw, resultMap, defaultResultHandler, this.rowBounds, (ResultMapping)null);
                    multipleResults.add(defaultResultHandler.getResultList());
                } else {
                    this.handleRowValues(rsw, resultMap, this.resultHandler, this.rowBounds, (ResultMapping)null);
                }
            } finally {
                this.closeResultSet(rsw.getResultSet());
            }
    
        }
    
    private void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
            if(resultMap.hasNestedResultMaps()) {
                this.ensureNoRowBounds();
                this.checkResultHandler();
                this.handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
            } else {
                this.handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
            }
    
        }
    
       private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
            DefaultResultContext<Object> resultContext = new DefaultResultContext();
            this.skipRows(rsw.getResultSet(), rowBounds);
            Object rowValue = null;
    
            while(this.shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
                ResultMap discriminatedResultMap = this.resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, (String)null);
                CacheKey rowKey = this.createRowKey(discriminatedResultMap, rsw, (String)null);
                Object partialObject = this.nestedResultObjects.get(rowKey);
                if(this.mappedStatement.isResultOrdered()) {
                    if(partialObject == null && rowValue != null) {
                        this.nestedResultObjects.clear();
                        this.storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
                    }
            //获取行的值
                    rowValue = this.getRowValue(rsw, discriminatedResultMap, rowKey, (String)null, partialObject);
                } else {
                    rowValue = this.getRowValue(rsw, discriminatedResultMap, rowKey, (String)null, partialObject);
                    if(partialObject == null) {
                        this.storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
                    }
                }
            }
    
            if(rowValue != null && this.mappedStatement.isResultOrdered() && this.shouldProcessMoreRows(resultContext, rowBounds)) {
                this.storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
            }
    
        }
        String resultMapId = resultMap.getId();
            Object resultObject = partialObject;
            if(partialObject != null) {
                MetaObject metaObject = this.configuration.newMetaObject(partialObject);
                this.putAncestor(partialObject, resultMapId, columnPrefix);
                this.applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
                this.ancestorObjects.remove(resultMapId);
            } else {
                ResultLoaderMap lazyLoader = new ResultLoaderMap();
                resultObject = this.createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
                if(resultObject != null && !this.typeHandlerRegistry.hasTypeHandler(resultMap.getType())) {
                    MetaObject metaObject = this.configuration.newMetaObject(resultObject);
                    boolean foundValues = !resultMap.getConstructorResultMappings().isEmpty();
                    if(this.shouldApplyAutomaticMappings(resultMap, true)) {
                        foundValues = this.applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
                    }
    
                    foundValues = this.applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
                    this.putAncestor(resultObject, resultMapId, columnPrefix);
                    foundValues = this.applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
                    this.ancestorObjects.remove(resultMapId);
                    foundValues = lazyLoader.size() > 0 || foundValues;
                    resultObject = foundValues?resultObject:null;
                }
    
                if(combinedKey != CacheKey.NULL_CACHE_KEY) {
                    this.nestedResultObjects.put(combinedKey, resultObject);
                }
            }
    
            return resultObject;
        }
    
    
    private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
            return resultMap.getAutoMapping() != null?resultMap.getAutoMapping().booleanValue():(isNested?AutoMappingBehavior.FULL == this.configuration.getAutoMappingBehavior():AutoMappingBehavior.NONE != this.configuration.getAutoMappingBehavior());
        }
     private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
            List<DefaultResultSetHandler.UnMappedColumAutoMapping> autoMapping = this.createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
            boolean foundValues = false;
            if(autoMapping.size() > 0) {
                Iterator i$ = autoMapping.iterator();
    
                while(true) {
               //这里使用了内部类对参数和结果集进行映射
                   DefaultResultSetHandler.UnMappedColumAutoMapping mapping;
                    Object value;
                    do {
                        if(!i$.hasNext()) {
                            return foundValues;
                        }
    
                        mapping = (DefaultResultSetHandler.UnMappedColumAutoMapping)i$.next();
                        value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
                    } while(value == null && !this.configuration.isCallSettersOnNulls());
    
                    if(value != null || !mapping.primitive) {
                        metaObject.setValue(mapping.property, value);
                    }
    
                    foundValues = true;
                }
            } else {
                return foundValues;
            }
        }
     private static class UnMappedColumAutoMapping {
            private final String column;
            private final String property;
            private final TypeHandler<?> typeHandler;
            private final boolean primitive;
    
        //此处才类型器对结果进行映射
            public UnMappedColumAutoMapping(String column, String property, TypeHandler<?> typeHandler, boolean primitive) {
                this.column = column;
                this.property = property;
                this.typeHandler = typeHandler;
                this.primitive = primitive;
            }
        }

     

    本文转自:https://blog.csdn.net/u014297148/article/details/78696096

    https://www.toutiao.com/a6599438299482292744/?tt_from=mobile_qq&utm_campaign=client_share&timestamp=1536563920&app=news_article&utm_source=mobile_qq&iid=43157585039&utm_medium=toutiao_android&group_id=6599438299482292744

  • 相关阅读:
    关于如何触发控件的事件
    MaxScript转换图像格式
    MaxScript装B技巧一则
    MaxScript.Net接收本地端口的消息执行
    MaxScript创建十二面体的代码
    MaxScript中GW使用范例一则
    Max里,Mesh真是高级自由度啊
    显示当前秒数的MaxScript
    Max2010的activex以及.net界面乱码解决方式
    半夜失眠,码点关于技术美术的字
  • 原文地址:https://www.cnblogs.com/nizuimeiabc1/p/9643109.html
Copyright © 2011-2022 走看看