Mybatis-Mapper各类标签封装类源码解析

Mybatis3.5.1源码分析

  1. Mybatis-SqlSessionFactoryBuilder,XMLConfigBuilder,XPathParser源码解析
  2. Mybatis-Configuration源码解析
  3. Mybatis-事务对象源码解析
  4. Mybatis-数据源源码解析
  5. Mybatis缓存策略源码解析
  6. Mybatis-DatabaseIdProvider源码解析
  7. Mybatis-TypeHandler源码解析
  8. Mybatis-Reflector源码解析
  9. Mybatis-ObjectFactory,ObjectWrapperFactory源码分析
  10. Mybatis-Mapper各类标签封装类源码解析
  11. Mybatis-XMLMapperBuilder,XMLStatmentBuilder源码分析
  12. Mybatis-MapperAnnotationBuilder源码分析
  13. [Mybatis-MetaObject,MetaClass源码解析]https://www.jianshu.com/p/f51fa552f30a)
  14. Mybatis-LanguageDriver源码解析
  15. Mybatis-SqlSource源码解析
  16. Mybatis-SqlNode源码解析
  17. Mybatis-KeyGenerator源码解析
  18. Mybatis-Executor源码解析
  19. Mybatis-ParameterHandler源码解析
  20. Mybatis-StatementHandler源码解析
  21. Mybatis-DefaultResultSetHandler(一)源码解析
  22. Mybatis-DefaultResultSetHandler(二)源码解析
  23. Mybatis-ResultHandler,Cursor,RowBounds 源码分析
  24. Mybatis-MapperProxy源码解析
  25. Mybatis-SqlSession源码解析
  26. Mybatis-Interceptor源码解析

ParameterMap

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.mapping;

import java.util.Collections;
import java.util.List;

import org.apache.ibatis.session.Configuration;

/**
 * 参数映射信息封装类,Mapper.xml的parameterMap标签
 * @author Clinton Begin
 */
public class ParameterMap {

  /**
   * ParameterMap标签的ID属性
   */
  private String id;

  /**
   * ParamterMap标签的type属性,即参数类型
   */
  private Class type;

  /**
   * ParamterMap标签的所有paramter标签,即参数的所有属性列表
   */
  private List parameterMappings;

  private ParameterMap() {
  }

  /**
   * ParameterMap的构造器
   */
  public static class Builder {
    private ParameterMap parameterMap = new ParameterMap();

    /**
     *
     * @param configuration 这个参数已经不用了,很有可能后面的版本去掉
     * @param id ParameterMap标签的ID属性
     * @param type ParamterMap标签的type属性,即参数类型
     * @param parameterMappings ParamterMap标签的所有paramter标签,即参数的所有属性列表
     */
    public Builder(Configuration configuration, String id, Class type, List parameterMappings) {
      parameterMap.id = id;
      parameterMap.type = type;
      parameterMap.parameterMappings = parameterMappings;
    }

    /**
     * 返回参数类型
     */
    public Class type() {
      return parameterMap.type;
    }

    public ParameterMap build() {
      //lock down collections 锁定集合
      /**
       *  Collections.unmodifiableList方法会将传进来的集合变成只读的集合,
       *  只要改变该集合都会抛出UnsupportedOperationException。
       *  总之,可以保证对象的list内容不被意料之外地修改,保证对象的封装性
       */
      parameterMap.parameterMappings = Collections.unmodifiableList(parameterMap.parameterMappings);
      return parameterMap;
    }
  }

  public String getId() {
    return id;
  }

  public Class getType() {
    return type;
  }

  public List getParameterMappings() {
    return parameterMappings;
  }

}

ParameterMapping

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.mapping;

import java.sql.ResultSet;

import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

/**
 * 参数映射
 * 

* 对应于Mapper.xml的: * <parameter property="" resultMap="" javaType="" typeHandler="" jdbcType="" mode="" scale=""></parameter> *

*

* 参考博客:https://blog.csdn.net/L_Sail/article/details/73824674 *

* @author Clinton Begin */ public class ParameterMapping { private Configuration configuration; /** * 属性名 */ private String property; /** * mode 属性允许你指定 IN,OUT 或 INOUT 参数。如果参数为 OUT 或 INOUT, * 参数对象属性的真实值将会被改变,就像你在获取输出参数时所期望的那样。 * 如果 mode 为 OUT(或 INOUT),而且 jdbcType 为 CURSOR(也就是 Oracle 的 REFCURSOR), * 必须指定一个 resultMap 来映射结果集到参数类型 */ private ParameterMode mode; /** * java类型 */ private Class javaType = Object.class; /** * jdbc类型 */ private JdbcType jdbcType; /** * 小数点后保留的位数 */ private Integer numericScale; /** * 类型处理器 */ private TypeHandler typeHandler; /** * 结果映射ID */ private String resultMapId; /** * jdbc类型名, SQL 结构类型的完全限定名称 *

* 作用于CallableStatement.registerOutParameter (int parameterIndex, int sqlType, String typeName)方法的 * typeName参数:
* 在执行存储过程调用之前,必须显式调用 registerOutParameter 为每个 OUT 参数注册来自 java.sql.Types 的类型。 * 对于用户定义的参数,还应该提供该参数的完全限定 SQL 类型名称,而 REF 参数则要求提供所引用类型的完全限定类型名称。 * 不需要类型代码和类型名称信息的 JDBC 驱动程序可以忽略它。不过,为了便于移植,应用程序应该为用户定义的参数和 REF 参数提供这些值。 *

*/ private String jdbcTypeName; /** * 表达式 */ private String expression; private ParameterMapping() { } public static class Builder { private ParameterMapping parameterMapping = new ParameterMapping(); /** * * @param configuration mybatis的配置信息类 * @param property 属性名 * @param typeHandler 属性类型处理器 */ public Builder(Configuration configuration, String property, TypeHandler typeHandler) { parameterMapping.configuration = configuration; parameterMapping.property = property; parameterMapping.typeHandler = typeHandler; parameterMapping.mode = ParameterMode.IN; } /** * * @param configuration mybatis的配置信息类 * @param property 属性名 * @param javaType 属性类型 */ public Builder(Configuration configuration, String property, Class javaType) { parameterMapping.configuration = configuration; parameterMapping.property = property; parameterMapping.javaType = javaType; parameterMapping.mode = ParameterMode.IN; } /** * mode 属性允许你指定 IN,OUT 或 INOUT 参数。如果参数为 OUT 或 INOUT,参数对象属性的真实值将会被改变,就像你在获取输出参数时所期望的那样。 * 如果 mode 为 OUT(或 INOUT),而且 jdbcType 为 CURSOR(也就是 Oracle 的 REFCURSOR),你必须指定一个 resultMap 来映射结果集到参数类型 */ public Builder mode(ParameterMode mode) { parameterMapping.mode = mode; return this; } /** * 属性类型 */ public Builder javaType(Class javaType) { parameterMapping.javaType = javaType; return this; } /** * 属性的jdbcType */ public Builder jdbcType(JdbcType jdbcType) { parameterMapping.jdbcType = jdbcType; return this; } /** * 参数的属性的小数点保留的位数 */ public Builder numericScale(Integer numericScale) { parameterMapping.numericScale = numericScale; return this; } /** * 参数的属性对应的结果映射ID */ public Builder resultMapId(String resultMapId) { parameterMapping.resultMapId = resultMapId; return this; } /** * 参数的属性对应的TypeHandler */ public Builder typeHandler(TypeHandler typeHandler) { parameterMapping.typeHandler = typeHandler; return this; } /** * 参数的属性对应的jdbcType名 */ public Builder jdbcTypeName(String jdbcTypeName) { parameterMapping.jdbcTypeName = jdbcTypeName; return this; } /** * 参数的属性正则表达式 */ public Builder expression(String expression) { parameterMapping.expression = expression; return this; } /** * 构建ParameterMapping *

* 在调用其ParameterMapping.Builder的构造方法时,就已经构建了parameterMapping。 * 而方法时就是返回这个paramterMapping,在返回之前,会检查有没有设置TypeHandler,没有的 * 话,会尝试根据javaType从TypeHandler注册器中获取对应javaType的TypeHandler实例. * 然后 检查一下业务需求所需要的属性是否缺漏,缺漏的抛出异常。如 *

*
    *
  1. 如果是javaType为ResultSet的时候,需要设置resultMapId属性,因为需要根据resultMap来映射获取数据。 * 否则抛出异常
  2. *
  3. 如果是javaType为其他类型是,必须要有对应其类型的typeHandler的实例。否则抛出异常
  4. *
*/ public ParameterMapping build() { //解析获取TypeHandler实例 resolveTypeHandler(); // 检查一下业务需求所需要的属性是否缺漏,缺漏的抛出异常 validate(); return parameterMapping; } /** * 检查一下业务需求所需要的属性是否缺漏 *

* 如果是javaType为ResultSet的时候,需要设置resultMapId属性,因为需要根据resultMap来映射获取数据。 * 否则抛出异常 *

*

* 如果是javaType为其他类型是,必须要有对应其类型的typeHandler的实例。否则抛出异常 *

*/ private void validate() { //当jdbcType为JdbcType.CURSOR是,javaType就会是ResultSet if (ResultSet.class.equals(parameterMapping.javaType)) { //如果是ResultSet就必须要有resultMapId,因为需要根据resultMap来映射获取数据。 if (parameterMapping.resultMapId == null) { throw new IllegalStateException("Missing resultmap in property '" + parameterMapping.property + "'. " + "Parameters of type java.sql.ResultSet require a resultmap."); } } else { //javaType为其他类型时,必须要有对应其类型的typeHandler的实例。 if (parameterMapping.typeHandler == null) { throw new IllegalStateException("Type handler was null on parameter mapping for property '" + parameterMapping.property + "'. It was either not specified and/or could not be found for the javaType (" + parameterMapping.javaType.getName() + ") : jdbcType (" + parameterMapping.jdbcType + ") combination."); } } } /** * 解析获取TypeHandler实例 *

* 在typeHandler为null且有javaType的情况下才会尝试从TypeHandler注册器获取对应的TypeHandler实例 *

*/ private void resolveTypeHandler() { if (parameterMapping.typeHandler == null && parameterMapping.javaType != null) { Configuration configuration = parameterMapping.configuration; TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); //只是获取typeHandler,没有注册 parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType); } } } public String getProperty() { return property; } /** * Used for handling output of callable statements. * @return */ public ParameterMode getMode() { return mode; } /** * Used for handling output of callable statements. * @return */ public Class getJavaType() { return javaType; } /** * Used in the UnknownTypeHandler in case there is no handler for the property type. * @return */ public JdbcType getJdbcType() { return jdbcType; } /** * Used for handling output of callable statements. * @return */ public Integer getNumericScale() { return numericScale; } /** * Used when setting parameters to the PreparedStatement. * @return */ public TypeHandler getTypeHandler() { return typeHandler; } /** * Used for handling output of callable statements. * @return */ public String getResultMapId() { return resultMapId; } /** * Used for handling output of callable statements. * @return */ public String getJdbcTypeName() { return jdbcTypeName; } /** * Not used * @return */ public String getExpression() { return expression; } @Override public String toString() { final StringBuilder sb = new StringBuilder("ParameterMapping{"); //sb.append("configuration=").append(configuration); // configuration doesn't have a useful .toString() sb.append("property='").append(property).append('\''); sb.append(", mode=").append(mode); sb.append(", javaType=").append(javaType); sb.append(", jdbcType=").append(jdbcType); sb.append(", numericScale=").append(numericScale); //sb.append(", typeHandler=").append(typeHandler); // typeHandler also doesn't have a useful .toString() sb.append(", resultMapId='").append(resultMapId).append('\''); sb.append(", jdbcTypeName='").append(jdbcTypeName).append('\''); sb.append(", expression='").append(expression).append('\''); sb.append('}'); return sb.toString(); } }

ResultMap

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.mapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.reflection.ParamNameUtil;
import org.apache.ibatis.session.Configuration;

/**
 * 结果映射信息封装类,Mapper.xml的resultMap标签信息封装类对象
 * @author Clinton Begin
 */
public class ResultMap {
  private Configuration configuration;

  /**
   * resultMap标签的Id属性
   */
  private String id;
  /**
   * resultMap标签的type属性,resultMap的java类型
   */
  private Class type;
  /**
   * 结果映射
   */
  private List resultMappings;
  /**
   * id结果映射
   */
  private List idResultMappings;
  /**
   * 构造函数结果映射,
   * 

* 存放着带有构造函数标记ResultFlag.CONSTRUCTOR的resultMapping *

*/ private List constructorResultMappings; /** * 属性结果映射。 *

将没有构造函数标记ResultFalg.CONSTRUCTOR的resultMapping添加到propertyResultMapping, * 没有构造函数标记ResultFalg.CONSTRUCTOR的resultMapping其实可以认为就是resultMap标签 * 下的result标签和id标签

*/ private List propertyResultMappings; /** * 映射列 *

* {@link #resultMappings}的所有column属性集合,包括嵌套的reusltMapping的column, * 所保存的列是以大写形式保存 *

*/ private Set mappedColumns; /** * 映射属性,存放着所有resultMapping的所有propery */ private Set mappedProperties; /** * 鉴别器 */ private Discriminator discriminator; /** * 有嵌套映射结果,判断reusltMapping中有没有设置嵌套的 resultMap id */ private boolean hasNestedResultMaps; /** * 有嵌套查询,判断reusltMapping中有没有设置select属性 */ private boolean hasNestedQueries; /** * 自动映射 */ private Boolean autoMapping; private ResultMap() { } public static class Builder { private static final Log log = LogFactory.getLog(Builder.class); private ResultMap resultMap = new ResultMap(); /** * * @param configuration mybatis全局配置 * @param id resultMap标签的ID属性 * @param type resultMap标签的type属性,resultMap的java类型 * @param resultMappings 结果元素映射集合 */ public Builder(Configuration configuration, String id, Class type, List resultMappings) { this(configuration, id, type, resultMappings, null); } /** * * @param configuration mybatis全局配置 * @param id resultMap标签的ID属性 * @param type resultMap标签的type属性,resultMap的java类型 * @param resultMappings 结果元素映射集合 * @param autoMapping 自动映射 */ public Builder(Configuration configuration, String id, Class type, List resultMappings, Boolean autoMapping) { resultMap.configuration = configuration; resultMap.id = id; resultMap.type = type; resultMap.resultMappings = resultMappings; resultMap.autoMapping = autoMapping; } /** * 鉴别器 * @param discriminator 鉴别器 * @return */ public Builder discriminator(Discriminator discriminator) { resultMap.discriminator = discriminator; return this; } /** * 返回resultMap的java类型 * @return {@link #resultMap#type} */ public Class type() { return resultMap.type; } /** * 构建resultMap * */ public ResultMap build() { //验证Id,Id是找到这个reusltMap的关键,不可以没有。 if (resultMap.id == null) { throw new IllegalArgumentException("ResultMaps must have an id"); } //给定下面属性一个空集合实例 resultMap.mappedColumns = new HashSet<>(); resultMap.mappedProperties = new HashSet<>(); resultMap.idResultMappings = new ArrayList<>(); resultMap.constructorResultMappings = new ArrayList<>(); resultMap.propertyResultMappings = new ArrayList<>(); //存放着带有构造函数标记的ResultMapping的property final List constructorArgNames = new ArrayList<>(); for (ResultMapping resultMapping : resultMap.resultMappings) { //有嵌套查询标记更新 resultMap.hasNestedQueries = resultMap.hasNestedQueries || resultMapping.getNestedQueryId() != null; //有嵌套ResultMap更新 resultMap.hasNestedResultMaps = resultMap.hasNestedResultMaps || (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null); /** * 将column添加到ResultMap.mappedColumn列表中,这个reusltMapping是个组合的reusltMapping, * 也会将组合的reusltMapping的column添加上去 */ final String column = resultMapping.getColumn(); if (column != null) { resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH)); } else if (resultMapping.isCompositeResult()) { for (ResultMapping compositeResultMapping : resultMapping.getComposites()) { final String compositeColumn = compositeResultMapping.getColumn(); if (compositeColumn != null) { resultMap.mappedColumns.add(compositeColumn.toUpperCase(Locale.ENGLISH)); } } } //将resultMapping的property添加到mappedProperties final String property = resultMapping.getProperty(); if (property != null) { resultMap.mappedProperties.add(property); } //将带有构造函数标记ResultFlag.CONSTRUCTOR的resultMapping添加到constructorResultMapping if (resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) { resultMap.constructorResultMappings.add(resultMapping); //添加带有构造函数标记ResultFlag.CONSTRUCTOR的resultMapping的property if (resultMapping.getProperty() != null) { constructorArgNames.add(resultMapping.getProperty()); } } else { /** *将没有构造函数标记ResultFalg.CONSTRUCTOR的resultMapping添加到propertyResultMapping, * 没有构造函数标记ResultFalg.CONSTRUCTOR的resultMapping其实可以认为就是resultMap标签 * 下的result标签和id标签 */ resultMap.propertyResultMappings.add(resultMapping); } //将带有ID标记ResultFlag.ID的resultMapping添加的idResultMapping if (resultMapping.getFlags().contains(ResultFlag.ID)) { resultMap.idResultMappings.add(resultMapping); } } //TODO 为啥在没有获取到带有ID标记ResultFlag.ID的resultMapping时就添加所有resultMaping? if (resultMap.idResultMappings.isEmpty()) { resultMap.idResultMappings.addAll(resultMap.resultMappings); } if (!constructorArgNames.isEmpty()) { /** * 获取对应construtorArgNames的构造函数的参数名列表,这里忽略constructorArgNames的元素顺序是否和 * 对应的构造函数的参数顺序对应,只对应他们的类型和参数名 */ final List actualArgNames = argNamesOfMatchingConstructor(constructorArgNames); /** * 这个异常触发条件我觉得会很容易触发的。 * 1.在如果在mybatis-config.xml文件中设置了useActualParamName为false的时候,resultMap对应的 * java类型的构造函数的参数又没有加上@param注解时,就会导致和constructorArgNames匹配不上。 */ if (actualArgNames == null) { throw new BuilderException("Error in result map '" + resultMap.id + "'. Failed to find a constructor in '" + resultMap.getType().getName() + "' by arg names " + constructorArgNames + ". There might be more info in debug log."); } //让constructorResultMapping根据构造函数的参数名列表actualArgNames进行排序。 resultMap.constructorResultMappings.sort((o1, o2) -> { int paramIdx1 = actualArgNames.indexOf(o1.getProperty()); int paramIdx2 = actualArgNames.indexOf(o2.getProperty()); return paramIdx1 - paramIdx2; }); } // lock down collections resultMap.resultMappings = Collections.unmodifiableList(resultMap.resultMappings); resultMap.idResultMappings = Collections.unmodifiableList(resultMap.idResultMappings); resultMap.constructorResultMappings = Collections.unmodifiableList(resultMap.constructorResultMappings); resultMap.propertyResultMappings = Collections.unmodifiableList(resultMap.propertyResultMappings); resultMap.mappedColumns = Collections.unmodifiableSet(resultMap.mappedColumns); return resultMap; } /** * 匹配构造函数的参数名称 * @param constructorArgNames 带有构造函数标记的ResultMapping的property集合 * @return 返回已经匹配验证成功的构造函数的参数名称,在匹配验证不成功的时候会返回null */ private List argNamesOfMatchingConstructor(List constructorArgNames) { Constructor[] constructors = resultMap.type.getDeclaredConstructors(); for (Constructor constructor : constructors) { Class[] paramTypes = constructor.getParameterTypes(); if (constructorArgNames.size() == paramTypes.length) { List paramNames = getArgNames(constructor); /** * paramNames有可能返回args0,args1...,这个时候containsAll返回false,使得整个方法返回null。 * 这里argTypesMatch方法并不会接收到paramNames为args0,args1...的情况,因为这里这里使用'&&', * 在containAll返回false的时候,是不会执行argTypesMatch方法。 */ if (constructorArgNames.containsAll(paramNames) && argTypesMatch(constructorArgNames, paramTypes, paramNames)) { return paramNames; } } } return null; } /** * 匹配构造函数的参数类型 * @param constructorArgNames 带有构造函数标记的ResultMapping的property集合 * @param paramTypes 构造函数的所有参数的类型 * @param paramNames 构造函数的所有参数的参数名 * @return 在 {@link #resultMap#constructorResultMappings} 的所有javaType与 * paramTypes取得的类型在类型上都相等的情况下就会返回true */ private boolean argTypesMatch(final List constructorArgNames, Class[] paramTypes, List paramNames) { for (int i = 0; i < constructorArgNames.size(); i++) { /** * 从constructorArgNames获取i位置的property,再从paramNames获取property对应的位置, * 再从paramTypes取得该位置对应的类型 */ Class actualType = paramTypes[paramNames.indexOf(constructorArgNames.get(i))]; //从构造函数ResultMapping中获取i位置的ResultMapping的javaType Class specifiedType = resultMap.constructorResultMappings.get(i).getJavaType(); /** * 这里判断不对应的情况下是不会抛出异常,只会打印log,并返回false,之所以没有抛出异常时是因为 * 统一交给了build方法抛出异常,这里只是简单的调用Class#equal方法,Class并没有对 * equal方法进行重写,所以equal方法相当于'=='的判断结果,也就是说这里没有考虑到父子类的情况。 * * 这里不存在因为顺序不一致而导致不相等的情况,因为actualType的通过constructorArgNames的位置获取的, * 而constructorArgNames和resultMap.constructorResultMappings同一个循环遍历下填充元素的,所以 * constructorArgNames和resultMap.constructorResultMappings的元素位置是一致的。 */ if (!actualType.equals(specifiedType)) { if (log.isDebugEnabled()) { log.debug("While building result map '" + resultMap.id + "', found a constructor with arg names " + constructorArgNames + ", but the type of '" + constructorArgNames.get(i) + "' did not match. Specified: [" + specifiedType.getName() + "] Declared: [" + actualType.getName() + "]"); } return false; } } return true; } /** * 获取构造函数的参数名 * @param constructor {@link #type} 的构造函数 * @return *
    *
  1. 尝试获取 {@code constructor} 的参数的 {@link Param} 作为参数名。
  2. *
  3. 在开启了 {@link #configuration#useActualParamName} 情况下,尝试获取 {@code constructor} 的参数名作为参数名
  4. *
  5. 最后方案:用"arg" + 参数索引作为参数名
  6. *
*/ private List getArgNames(Constructor constructor) { List paramNames = new ArrayList<>(); List actualParamNames = null; //获取constructor每个参数的注解 final Annotation[][] paramAnnotations = constructor.getParameterAnnotations(); int paramCount = paramAnnotations.length; for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) { String name = null; //找到@Param注解并把其value赋给name for (Annotation annotation : paramAnnotations[paramIndex]) { if (annotation instanceof Param) { name = ((Param) annotation).value(); break; } } //在开启了configuration#useActualParamName情况下,会使用在构造函数的参数名赋值给name if (name == null && resultMap.configuration.isUseActualParamName()) { if (actualParamNames == null) { actualParamNames = ParamNameUtil.getParamNames(constructor); } //要保证构造函数的参数名数量是大于参数索引paramIndex,否则在获取参数名时会抛出异常 if (actualParamNames.size() > paramIndex) { name = actualParamNames.get(paramIndex); } } /** * 1,在仍然获取不到name的情况下,会以'arg'+paramIndex 作为name * 2.添加到paramNames */ paramNames.add(name != null ? name : "arg" + paramIndex); } return paramNames; } } public String getId() { return id; } public boolean hasNestedResultMaps() { return hasNestedResultMaps; } public boolean hasNestedQueries() { return hasNestedQueries; } public Class getType() { return type; } public List getResultMappings() { return resultMappings; } public List getConstructorResultMappings() { return constructorResultMappings; } public List getPropertyResultMappings() { return propertyResultMappings; } public List getIdResultMappings() { return idResultMappings; } public Set getMappedColumns() { return mappedColumns; } public Set getMappedProperties() { return mappedProperties; } public Discriminator getDiscriminator() { return discriminator; } public void forceNestedResultMaps() { hasNestedResultMaps = true; } public Boolean getAutoMapping() { return autoMapping; } }

Discriminator

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.mapping;

import java.util.Collections;
import java.util.Map;

import org.apache.ibatis.session.Configuration;

/**
 * 鉴别器
 * 用于对一个查询可能出现的不同结果集做鉴别,根据具体的条件为 resultMap 动态选择返回值类型。
 * 

* eg:
* <discriminator javaType="int" column="type">
*   <case value="1" resultType="Apple"/>
*   <case value="2" resultType="Banana"/>
* <discriminator/> *

* *

* 参考博客:https://blog.csdn.net/weixin_36210698/article/details/83508113 *

* @author Clinton Begin */ public class Discriminator { /** * ResutMap标签的属性标签封装 */ private ResultMapping resultMapping; /** * case标签信息封装,映射 *

* key=case标签的value属性,value=命名空间+case标签的resultMap属性(reusltMapId), *

*/ private Map discriminatorMap; Discriminator() { } public static class Builder { private Discriminator discriminator = new Discriminator(); public Builder(Configuration configuration, ResultMapping resultMapping, Map discriminatorMap) { discriminator.resultMapping = resultMapping; discriminator.discriminatorMap = discriminatorMap; } public Discriminator build() { assert discriminator.resultMapping != null; assert discriminator.discriminatorMap != null; assert !discriminator.discriminatorMap.isEmpty(); //lock down map discriminator.discriminatorMap = Collections.unmodifiableMap(discriminator.discriminatorMap); return discriminator; } } public ResultMapping getResultMapping() { return resultMapping; } public Map getDiscriminatorMap() { return discriminatorMap; } public String getMapIdFor(String s) { return discriminatorMap.get(s); } }

MappedStatement

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.mapping;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;

/**
 * 

* Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 *

*

* MappedStatement类在Mybatis框架中用于表示XML文件中一个sql语句节点, * 即一个、或者标签。Mybatis框架在初始化阶段会对XML配置文件进行读取 * ,将其中的sql语句节点对象化为一个个MappedStatement对象。 *

* @author Clinton Begin */ public final class MappedStatement { /** * 资源路径,当前项目,有可能是java文件也有可能是.xml文件 */ private String resource; /** * mybatis全局配置信息 */ private Configuration configuration; /** * 节点中的id属性加要命名空间 */ private String id; /** *

select标签的fetchSize属性

*
*

* 这是尝试影响驱动程序每次批量返回的结果行数和这个设置值相等。默认值为 unset(依赖驱动)。 *

*
*

* 假设fetchSize为5,查询总记录数为100,每批5次返回给你,最后结果还是总记录数,只是提高点查询的速度而已 *

*
*

* MySQL不支持fetchSize,默认为一次性取出所有数据。所以容易导致OOM, * 如果是Oracle的话就是默认取出fetchSize条数据。 * 裸露JDBC防止OOM可以调用statement的enableStreamingResults方法, * MyBatis应该在<select fetchSize="-2147483648">。 *

*/ private Integer fetchSize; /** * 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。 * 默认值为 unset(依赖驱动)。 */ private Integer timeout; /** *
    *
  1. STATEMENT:对应于Statement对象,有SQL注入的风险
  2. *
  3. PREPARED:PreparedStatement,预编译处理
  4. *
  5. CALLABLE:CallableStatement一般调用存储过程的时候使用
  6. *
* 默认是PREPARED */ private StatementType statementType; /** * 其实的就是{@link java.sql.ResultSet}的常量,只不过Mybatis对其常量进行封装成枚举。 *
    *
  1. DEFAULT:依赖驱动
  2. *
  3. FORWARD_ONLY:结果集的游标只能向下滚动
  4. *
  5. SCROLL_INSENSITIVE:结果集的游标可以上下移动,当数据库变化时,当前结果集不变
  6. *
  7. SCROLL_SENSITIVE:返回可滚动的结果集,当数据库变化时,当前结果集同步改变
  8. *
*/ private ResultSetType resultSetType; /** * 构建动态SQL */ private SqlSource sqlSource; /** * 每条语句都对就一个缓存,如果有的话 */ private Cache cache; /** * 参数映射信息封装类,Mapper.xml的parameterMap标签 */ private ParameterMap parameterMap; /** * 结果映射信息封装类,Mapper.xml的resultMap标签 集合 */ private List resultMaps; /** * 需要刷新缓存标记 *

* 如果配置了flushCacheRequired为true,则会在执行器执行之前就清空本地一级缓存,换句话说就是关闭一级缓存功能 *

*/ private boolean flushCacheRequired; /** * 启用缓存标记 */ private boolean useCache; /** * select标签 *

* 如果为 true,就是假设包含了嵌套结果集或是分组了,这样的话当返回一个主结果行的时候, * 就不会发生有对前面结果集的引用的情况。这就使得在获取嵌套的结果集的时候不至于导致内存不够用。 * 默认值:false。 *

*

* 参考博客:https://blog.csdn.net/isea533/article/details/51533296?utm_source=blogxgwz9 *

*/ private boolean resultOrdered; /** * SQL指令类型 *
    *
  1. UNKNOWN:未知
  2. *
  3. INSERT:插入
  4. *
  5. UPDATE:修改
  6. *
  7. DELETE:删除
  8. *
  9. SELECT:查询
  10. *
  11. FLUSH:刷新
  12. *
*/ private SqlCommandType sqlCommandType; /** * Key生成器 */ private KeyGenerator keyGenerator; /** * (仅对 insert 和 update 有用)唯一标记一个属性, * MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值, * 默认:unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 */ private String[] keyProperties; /** * (仅对 insert 和 update 有用)通过生成的键值设置表中的列名, * 这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。 * 如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表 */ private String[] keyColumns; /** * 有嵌套映射结果标记,这个标记除了ParamterMap里面的resultMap外还保护ParamterMap里面的resultMap的resultMap */ private boolean hasNestedResultMaps; /** * DML标签中配置的databaseId属性 */ private String databaseId; /** * 日志对象 */ private Log statementLog; /** * 语言驱动,默认是 {@link org.apache.ibatis.scripting.xmltags.XMLLanguageDriver} */ private LanguageDriver lang; /** * 结果集 */ private String[] resultSets; MappedStatement() { // constructor disabled } public static class Builder { /** * 默认对象 */ private MappedStatement mappedStatement = new MappedStatement(); /** * * @param configuration mybatis全局配置信息 * @param id 节点中的id属性加要命名空间 * @param sqlSource 构建动态SQL * @param sqlCommandType SQL指令类型 */ public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) { mappedStatement.configuration = configuration; mappedStatement.id = id; mappedStatement.sqlSource = sqlSource; mappedStatement.statementType = StatementType.PREPARED; mappedStatement.resultSetType = ResultSetType.DEFAULT; mappedStatement.parameterMap = new ParameterMap.Builder(configuration, "defaultParameterMap", null, new ArrayList<>()).build(); mappedStatement.resultMaps = new ArrayList<>(); mappedStatement.sqlCommandType = sqlCommandType; mappedStatement.keyGenerator = configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE; String logId = id; //加上全局日志的前缀 if (configuration.getLogPrefix() != null) { logId = configuration.getLogPrefix() + id; } mappedStatement.statementLog = LogFactory.getLog(logId); mappedStatement.lang = configuration.getDefaultScriptingLanguageInstance(); } public Builder resource(String resource) { mappedStatement.resource = resource; return this; } public String id() { return mappedStatement.id; } public Builder parameterMap(ParameterMap parameterMap) { mappedStatement.parameterMap = parameterMap; return this; } public Builder resultMaps(List resultMaps) { mappedStatement.resultMaps = resultMaps; for (ResultMap resultMap : resultMaps) { mappedStatement.hasNestedResultMaps = mappedStatement.hasNestedResultMaps || resultMap.hasNestedResultMaps(); } return this; } public Builder fetchSize(Integer fetchSize) { mappedStatement.fetchSize = fetchSize; return this; } public Builder timeout(Integer timeout) { mappedStatement.timeout = timeout; return this; } public Builder statementType(StatementType statementType) { mappedStatement.statementType = statementType; return this; } public Builder resultSetType(ResultSetType resultSetType) { mappedStatement.resultSetType = resultSetType == null ? ResultSetType.DEFAULT : resultSetType; return this; } public Builder cache(Cache cache) { mappedStatement.cache = cache; return this; } public Builder flushCacheRequired(boolean flushCacheRequired) { mappedStatement.flushCacheRequired = flushCacheRequired; return this; } public Builder useCache(boolean useCache) { mappedStatement.useCache = useCache; return this; } public Builder resultOrdered(boolean resultOrdered) { mappedStatement.resultOrdered = resultOrdered; return this; } public Builder keyGenerator(KeyGenerator keyGenerator) { mappedStatement.keyGenerator = keyGenerator; return this; } public Builder keyProperty(String keyProperty) { mappedStatement.keyProperties = delimitedStringToArray(keyProperty); return this; } public Builder keyColumn(String keyColumn) { mappedStatement.keyColumns = delimitedStringToArray(keyColumn); return this; } public Builder databaseId(String databaseId) { mappedStatement.databaseId = databaseId; return this; } public Builder lang(LanguageDriver driver) { mappedStatement.lang = driver; return this; } public Builder resultSets(String resultSet) { mappedStatement.resultSets = delimitedStringToArray(resultSet); return this; } /** * @deprecated Use {@link #resultSets} */ @Deprecated public Builder resulSets(String resultSet) { mappedStatement.resultSets = delimitedStringToArray(resultSet); return this; } public MappedStatement build() { assert mappedStatement.configuration != null; assert mappedStatement.id != null; assert mappedStatement.sqlSource != null; assert mappedStatement.lang != null; mappedStatement.resultMaps = Collections.unmodifiableList(mappedStatement.resultMaps); return mappedStatement; } } public KeyGenerator getKeyGenerator() { return keyGenerator; } public SqlCommandType getSqlCommandType() { return sqlCommandType; } public String getResource() { return resource; } public Configuration getConfiguration() { return configuration; } public String getId() { return id; } public boolean hasNestedResultMaps() { return hasNestedResultMaps; } public Integer getFetchSize() { return fetchSize; } public Integer getTimeout() { return timeout; } public StatementType getStatementType() { return statementType; } public ResultSetType getResultSetType() { return resultSetType; } public SqlSource getSqlSource() { return sqlSource; } public ParameterMap getParameterMap() { return parameterMap; } public List getResultMaps() { return resultMaps; } public Cache getCache() { return cache; } public boolean isFlushCacheRequired() { return flushCacheRequired; } public boolean isUseCache() { return useCache; } public boolean isResultOrdered() { return resultOrdered; } public String getDatabaseId() { return databaseId; } public String[] getKeyProperties() { return keyProperties; } public String[] getKeyColumns() { return keyColumns; } public Log getStatementLog() { return statementLog; } public LanguageDriver getLang() { return lang; } public String[] getResultSets() { return resultSets; } /** * @deprecated Use {@link #getResultSets()} */ @Deprecated public String[] getResulSets() { return resultSets; } /** * 构建BoundSql对象 * @param parameterObject 参数对象 * @return BoundSql对象 */ public BoundSql getBoundSql(Object parameterObject) { //获取可执行的SQL BoundSql boundSql = sqlSource.getBoundSql(parameterObject); List parameterMappings = boundSql.getParameterMappings(); //将参数映射加入到BoundSql,重新构建BoundSql对象 if (parameterMappings == null || parameterMappings.isEmpty()) { boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject); } //检查是否有嵌套的resultMap // check for nested result maps in parameter mappings (issue #30) for (ParameterMapping pm : boundSql.getParameterMappings()) { String rmId = pm.getResultMapId(); if (rmId != null) { ResultMap rm = configuration.getResultMap(rmId); if (rm != null) { hasNestedResultMaps |= rm.hasNestedResultMaps(); } } } return boundSql; } private static String[] delimitedStringToArray(String in) { if (in == null || in.trim().length() == 0) { return null; } else { return in.split(","); } } }

ResultMapping

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.mapping;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

/**
 * resultMap 子元素映射关系
 * @author Clinton Begin
 */
public class ResultMapping {

  /**
   * mybtais全局配置
   */
  private Configuration configuration;
  /**
   * 属性名
   */
  private String property;
  /**
   * 列名
   */
  private String column;
  /**
   * 属性的java类型
   */
  private Class javaType;
  /**
   * 属性的jdbc类型
   */
  private JdbcType jdbcType;
  /**
   * 类型转换器
   */
  private TypeHandler typeHandler;
  /**
   * 嵌套的resultMapId,【命名空间+resultMapId】
   */
  private String nestedResultMapId;
  /**
   * 嵌套的selectId,【命名空间+selectId】
   */
  private String nestedQueryId;
  /**
   * 不能为空的列名
    */
  private Set notNullColumns;
  /**
   * SQL的列名前缀
   */
  private String columnPrefix;
  /**
   * 属性标记
   */
  private List flags;
  /**
   * 组合ResultMaping列表
   */
  private List composites;
  /**
   * 指定用于加载复杂类型的结果集名字。
   */
  private String resultSet;
  /**
   * 指定外键对应的列名
   */
  private String foreignColumn;
  /**
   * 是否懒加载
   */
  private boolean lazy;

  ResultMapping() {
  }

  public static class Builder {
    private ResultMapping resultMapping = new ResultMapping();

    /**
     *
     * @param configuration mybatis全局配置信息
     * @param property 属性名
     * @param column 表列名
     * @param typeHandler 类型处理器
     */
    public Builder(Configuration configuration, String property, String column, TypeHandler typeHandler) {
      this(configuration, property);
      resultMapping.column = column;
      resultMapping.typeHandler = typeHandler;
    }

    /**
     *
     * @param configuration mybatis全局配置信息
     * @param property 属性名
     * @param column 表列名
     * @param javaType 属性的java类型
     */
    public Builder(Configuration configuration, String property, String column, Class javaType) {
      this(configuration, property);
      resultMapping.column = column;
      resultMapping.javaType = javaType;
    }

    /**
     * 
    *
  1. {@link #resultMapping#flags}初始化空的{@link ArrayList}
  2. *
  3. {@link #resultMapping#composites}初始化空的{@link ArrayList}
  4. *
  5. @{@link #resultMapping#lazy}初始为mybatis全局配置文件的 {@link Configuration#lazyLoadingEnabled} 属性设置
  6. *
* @param configuration mybatis全局配置信息 * @param property 属性名 */ public Builder(Configuration configuration, String property) { resultMapping.configuration = configuration; resultMapping.property = property; resultMapping.flags = new ArrayList<>(); resultMapping.composites = new ArrayList<>(); resultMapping.lazy = configuration.isLazyLoadingEnabled(); } /** * 属性的java类型 */ public Builder javaType(Class javaType) { resultMapping.javaType = javaType; return this; } /** * 属性的jdbc类型 */ public Builder jdbcType(JdbcType jdbcType) { resultMapping.jdbcType = jdbcType; return this; } /** * 嵌套的resultMapId */ public Builder nestedResultMapId(String nestedResultMapId) { resultMapping.nestedResultMapId = nestedResultMapId; return this; } /** * 嵌套的selectId */ public Builder nestedQueryId(String nestedQueryId) { resultMapping.nestedQueryId = nestedQueryId; return this; } /** * 集合的多结果集 */ public Builder resultSet(String resultSet) { resultMapping.resultSet = resultSet; return this; } /** * 指定外键对应的列名 */ public Builder foreignColumn(String foreignColumn) { resultMapping.foreignColumn = foreignColumn; return this; } /** * 获取指定的不为空才创建实例的列 */ public Builder notNullColumns(Set notNullColumns) { resultMapping.notNullColumns = notNullColumns; return this; } /** * 列前缀 */ public Builder columnPrefix(String columnPrefix) { resultMapping.columnPrefix = columnPrefix; return this; } /** * 属性标记 */ public Builder flags(List flags) { resultMapping.flags = flags; return this; } /** * 类型处理器 */ public Builder typeHandler(TypeHandler typeHandler) { resultMapping.typeHandler = typeHandler; return this; } /** * 组合RequestMapping列表 */ public Builder composites(List composites) { resultMapping.composites = composites; return this; } /** * 懒加载 */ public Builder lazy(boolean lazy) { resultMapping.lazy = lazy; return this; } /** * 构建出ResuatMapping实例。 *

* resultMapping在Builder初始化时已经创建了,这个方法用于返回resultMapping实例。 * 而且该方法会对flags,composites进行加锁,以防止在其他调用者修改。在typeHandler * 没有设置的情况下,也会在全局typeHandler注册器中找到对应javaType的typeHandlder实例。 * 也验证了一下属性设置的合法性,将不合法的属性设置抛出异常。 *

* @return */ public ResultMapping build() { // lock down collections 锁住集合,让flags,composites集合不能再发生任何更改。 resultMapping.flags = Collections.unmodifiableList(resultMapping.flags); resultMapping.composites = Collections.unmodifiableList(resultMapping.composites); //当typeHandler为null,会根据javaType来获取一个typeHandler实例赋值到typeHandler resolveTypeHandler(); //验证,不符合条件的,就会抛出异常中断执行。 validate(); return resultMapping; } /** * 验证,不符合下面的某一条件都会抛出 {@link IllegalStateException} 异常。 *
    *
  1. 不能同时定义 嵌套的selectId 和 嵌套的resultMapId
  2. *
  3. 在没有设置嵌套的selectId有没有设置嵌套的resultMapId的情况下,typeHandler不应该没有设置或者获取不到。
  4. *
  5. 列名是可选的在嵌套的resultMap组,但是不能在没有设置嵌套的resultMapId又没有设置组合的resultMap列表的情况下。
  6. *
  7. 有结果集结合的情况下,通过','隔开的列名与外键列名数保持一致。
  8. *
*/ private void validate() { // Issue #697: cannot define both nestedQueryId and nestedResultMapId //不能同时定义 嵌套的selectId 和 嵌套的resultMapId if (resultMapping.nestedQueryId != null && resultMapping.nestedResultMapId != null) { throw new IllegalStateException("Cannot define both nestedQueryId and nestedResultMapId in property " + resultMapping.property); } // Issue #5: there should be no mappings without typehandler //在没有设置嵌套的selectId有没有设置嵌套的resultMapId的情况下,typeHandler不应该没有设置或者获取不到。 if (resultMapping.nestedQueryId == null && resultMapping.nestedResultMapId == null && resultMapping.typeHandler == null) { throw new IllegalStateException("No typehandler found for property " + resultMapping.property); } // Issue #4 and GH #39: column is optional only in nested resultmaps but not in the rest //列名是可选的在嵌套的resultMap组,但是不能在没有设置嵌套的resultMapId又没有设置组合的resultMap列表的情况下。 if (resultMapping.nestedResultMapId == null && resultMapping.column == null && resultMapping.composites.isEmpty()) { throw new IllegalStateException("Mapping is missing column attribute for property " + resultMapping.property); } //有结果集结合的情况下,通过','隔开的列名与外键列名数保持一致。 if (resultMapping.getResultSet() != null) { int numColumns = 0; if (resultMapping.column != null) { numColumns = resultMapping.column.split(",").length; } int numForeignColumns = 0; if (resultMapping.foreignColumn != null) { numForeignColumns = resultMapping.foreignColumn.split(",").length; } if (numColumns != numForeignColumns) { throw new IllegalStateException("There should be the same number of columns and foreignColumns in property " + resultMapping.property); } } } /** * 解析TypeHadnler实例 *

* 当 {@link #typeHandler} 的为null时,该方法就会根据 {@link #javaType}去 * {@link #configuration}的TypeHandlerResgistry对应的typeHandler实例并赋值到{@link #typeHandler}。 *

*/ private void resolveTypeHandler() { if (resultMapping.typeHandler == null && resultMapping.javaType != null) { Configuration configuration = resultMapping.configuration; TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); resultMapping.typeHandler = typeHandlerRegistry.getTypeHandler(resultMapping.javaType, resultMapping.jdbcType); } } public Builder column(String column) { resultMapping.column = column; return this; } } public String getProperty() { return property; } public String getColumn() { return column; } public Class getJavaType() { return javaType; } public JdbcType getJdbcType() { return jdbcType; } public TypeHandler getTypeHandler() { return typeHandler; } public String getNestedResultMapId() { return nestedResultMapId; } public String getNestedQueryId() { return nestedQueryId; } public Set getNotNullColumns() { return notNullColumns; } public String getColumnPrefix() { return columnPrefix; } public List getFlags() { return flags; } public List getComposites() { return composites; } /** * 是否存在组合ResultMaping列表 * @return */ public boolean isCompositeResult() { return this.composites != null && !this.composites.isEmpty(); } public String getResultSet() { return this.resultSet; } public String getForeignColumn() { return foreignColumn; } public void setForeignColumn(String foreignColumn) { this.foreignColumn = foreignColumn; } public boolean isLazy() { return lazy; } public void setLazy(boolean lazy) { this.lazy = lazy; } /** * 判断属性名{@link #property} */ @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } ResultMapping that = (ResultMapping) o; if (property == null || !property.equals(that.property)) { return false; } return true; } /** * 判断属性名{@link #property} */ @Override public int hashCode() { if (property != null) { return property.hashCode(); } else if (column != null) { return column.hashCode(); } else { return 0; } } @Override public String toString() { final StringBuilder sb = new StringBuilder("ResultMapping{"); //sb.append("configuration=").append(configuration); // configuration doesn't have a useful .toString() sb.append("property='").append(property).append('\''); sb.append(", column='").append(column).append('\''); sb.append(", javaType=").append(javaType); sb.append(", jdbcType=").append(jdbcType); //sb.append(", typeHandler=").append(typeHandler); // typeHandler also doesn't have a useful .toString() sb.append(", nestedResultMapId='").append(nestedResultMapId).append('\''); sb.append(", nestedQueryId='").append(nestedQueryId).append('\''); sb.append(", notNullColumns=").append(notNullColumns); sb.append(", columnPrefix='").append(columnPrefix).append('\''); sb.append(", flags=").append(flags); sb.append(", composites=").append(composites); sb.append(", resultSet='").append(resultSet).append('\''); sb.append(", foreignColumn='").append(foreignColumn).append('\''); sb.append(", lazy=").append(lazy); sb.append('}'); return sb.toString(); } }

你可能感兴趣的:(Mybatis-Mapper各类标签封装类源码解析)