xyzxiafancai 2017-04-21
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来判断是否存在同一对象进而封装。