在前一章节mybatis进击四:原始SQL查询 ,我们写了一段原始的sql查询代码片段,其中有一个问题,就是结果集的处理非常繁琐,那么如何可以转换成自己的类对象呢?
首先我们先认识几个封装类ResultSetWrapper,ResultMap,ResultMapping
一、ResultSetWrapper
对java.sql.ResultSet进行了封装
// 保持对原有的ResultSet引用
private final ResultSet resultSet;
// 保持Configuration中配置的typeHandlerRegistry引用,方便查找属性的typeHandler
private final TypeHandlerRegistry typeHandlerRegistry;
// 类名
private final List<String> columnNames = new ArrayList<String>();
// 类名
private final List<String> classNames = new ArrayList<String>();
// jdbc类型
private final List<JdbcType> jdbcTypes = new ArrayList<JdbcType>();
// 保存 某个属性的typeHandler,相当于一个缓存
private final Map<String, Map<Class<?>, TypeHandler<?>>> typeHandlerMap = new HashMap<String, Map<Class<?>, TypeHandler<?>>>();
// 映射的列
private final Map<String, List<String>> mappedColumnNamesMap = new HashMap<String, List<String>>();
// 未映射到的值
private final Map<String, List<String>> unMappedColumnNamesMap = new HashMap<String, List<String>>();
二、ResultMap
对XML文件的中resultMap 的 解析后的对象
// 持有Configuration引用,注:Configuration是核心数据,可以发现,很多对象都保持着这个对象的引用
private Configuration configuration;
// 标识 id namespace + id
private String id;
// 对应的类型
private Class<?> type;
// xml中result的解析对象
private List<ResultMapping> resultMappings;
// <id> 标签,如果没有,则 是 resultMappings
private List<ResultMapping> idResultMappings;
// 处理<constructor>标签
private List<ResultMapping> constructorResultMappings;
// 不在<constructor>中的其他映射
private List<ResultMapping> propertyResultMappings;
// 列的映射
private Set<String> mappedColumns;
// 属性的映射
private Set<String> mappedProperties;
// 鉴别器,对于复杂属性的处理
private Discriminator discriminator;
// 嵌套result
private boolean hasNestedResultMaps;
private boolean hasNestedQueries;
// 是否自动映射,默认null
private Boolean autoMapping;
三、 ResultMapping
对XML 文件中 的 <result>标签的解析结果
//持有Configuration引用
private Configuration configuration;
//属性名
private String property;
// 列名
private String column;
// java类
private Class<?> javaType;
// jdbc 类
private JdbcType jdbcType;
// 处理handler,根据javaType 寻找,我们可以在<result>中指定自定义的handler
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;
四、DefaultResultSetHandler
对原始ResultSet的处理,其实就是将ResultSet根据ResultMap和ResultMapping转换成一个对象
对结果集的处理,是由DefaultResultSetHandler进行处理的
接着我们进入到对普通结果集的处理中(handleRowValuesForNestedResultMap 是对 负责结果集的处理)
最终通过以下语句为对象相应的字段赋值
metaObject.setValue(property, value);
当然我们会发现,这里不是一个简单的反射赋值,mybatis设计了自己的反射处理(之后再整理下这部分,看看他们为什么这么设计)
五、总结
通过上面的分析,简单的概述下
1、设计了一种文件形式,持有了列和属性的关系
2、抽象了TypeHandler,以应对不同类型的值的转换,同时支持扩展
3、通过反射调用,转换成设置的对象