Mybatis数据封装过程原理解析

mybatis封装数据过程:mybatis中大量使用了装饰设计模式。

1、最简单的一种情况:xml中没有配置resultMap也就是查询出来直接封装到javabean中。

mybatis源码:

DefaultResultSetHandler.class

//从resultSet的包装类ResultSetWrapper中查询出sql中写的所有column.
final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
    boolean foundValues = false;
    for (String columnName : unmappedColumnNames) {
      String propertyName = columnName;
      if (columnPrefix != null && columnPrefix.length() > 0) {
        // When columnPrefix is specified,
        // ignore columns without the prefix.
        if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
          propertyName = columnName.substring(columnPrefix.length());
        } else {
          continue;
        }
      }
      //从metaObject中查询出Object中是否有该property。metaObject是ObjectWrapper的包装类.ObjectWrapper是Object的包装类
      final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
      if (property != null && metaObject.hasSetter(property)) {
	//拿到字段类型
        final Class<?> propertyType = metaObject.getSetterType(property);
        if (typeHandlerRegistry.hasTypeHandler(propertyType)) {
	  //获取处理字段类型的typeHandler	
          final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
	  //获取值
          final Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
          if (value != null || configuration.isCallSettersOnNulls()) { // issue #377, call setter on nulls
            if (value != null || !propertyType.isPrimitive()) {
	    //设置值
              metaObject.setValue(property, value);
            }
            foundValues = true;
          }
        }
      }
    }

2、封装collection一对多关系或者一对一关系的原理:

首先项目加载的时候读取xml中的<resultMap>标签封装到ResultMap其中ResultMap中的每一个result对应ResultMapping.

public class ResultMap {
  private String id;
  private Class<?> type;
  private List<ResultMapping> resultMappings;
  private List<ResultMapping> idResultMappings;
  private List<ResultMapping> constructorResultMappings;
  private List<ResultMapping> propertyResultMappings;
  private Set<String> mappedColumns;
  private Discriminator discriminator;
  private boolean hasNestedResultMaps; //是否有嵌套标签
  private boolean hasNestedQueries;
  private Boolean autoMapping;
resultMap对应<resultMap>标签


public class ResultMapping {

  private Configuration configuration;
  private String property;
  private String column;
  private Class<?> javaType;
  private JdbcType jdbcType;
  private TypeHandler<?> typeHandler;
  private String nestedResultMapId;
  private String nestedQueryId;
  private Set<String> notNullColumns;
  private String columnPrefix;
  private List<ResultFlag> flags;
  private List<ResultMapping> composites;
  private String resultSet;
  private String foreignColumn;
  private boolean lazy;
ResultMapping 对应<ResultMap>标签下的<result标签><collection标签等>

public class DefaultResultSetHandler implements ResultSetHandler这个类是处理结果集映射的类,其中定义了两个Map:
private final Map<CacheKey, Object> nestedResultObjects = new HashMap<CacheKey, Object>(); 保存实体类对象在一对多关系映射的时候,首先从该Map中取对象,如果有就取出来,如果没有就新建。CacheKey根据主键生成。

  private final Map<CacheKey, Object> ancestorObjects = new HashMap<CacheKey, Object>();保存实体嵌套类的对象,先从该Map中根据CacheKey判断是否有对象,有则取出,没有则新建。CacheKey根据嵌套类的id生成。这也是为什么当配置collection的时候一定要配置id标签,因为封装一对多关系的时候是根据id来判断是否存在同一对象进而封装。

相关推荐