1 ResultSetHandler简介
- 处理Statement执行后产生的结果集,生成结果列表
- 处理存储过程执行后的输出参数
public interface ResultSetHandler {
// 将Statement执行后产生的结果集(可能有多个结果集)映射为结果列表
<E> List<E> handleResultSets(Statement var1) throws SQLException;
<E> Cursor<E> handleCursorResultSets(Statement var1) throws SQLException;
// 处理存储过程执行后的输出参数
void handleOutputParameters(CallableStatement var1) throws SQLException;
}
ResultSetHandler的具体实现类是DefaultResultSetHandler,其实现的步骤就是将Statement执行后的结果集,按照Mapper文件中resultMap配置的ResultType或ResultMap来封装成对应的对象,最后将封装的对象返回 。
但在解析结果值的时候还依赖一些其他的类。
-
ResultSetWrapper:ResultSet包装器,丰富ResultSet方法,包含了ResultSet相关元数据
-
ResultContext:结果值上下文,存储值结果值、总数等。
-
ResultHandler:结果处理器。做处理完的类型转换的结果,进行后置处理。
1.1 ResultSetWrapper
public class ResultSetWrapper {
/**
* 数据集
*/
private final ResultSet resultSet;
private final TypeHandlerRegistry typeHandlerRegistry;
/**
* 字段名集合
*/
private final List<String> columnNames = new ArrayList<>();
/**
* 字段对应的javaType类型名
*/
private final List<String> classNames = new ArrayList<>();
/**
* jdbcType
*/
private final List<JdbcType> jdbcTypes = new ArrayList<>();
// 类型处理器
private final Map<String, Map<Class<?>, TypeHandler<?>>> typeHandlerMap = new HashMap<>();
/**
* 针对当前ResultSet中,resultMap中映射的字段名
* key: resultMapId
* value:resultMap映射字段
*/
private final Map<String, List<String>> mappedColumnNamesMap = new HashMap<>();
/**
* 针对当前ResultSet中,resultMap中未映射的字段名
* key: resultMapId
* value:resultMap未映射字段
*/
private final Map<String, List<String>> unMappedColumnNamesMap = new HashMap<>();
public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
super();
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.resultSet = rs;
// 从ResultSet中获取元数据
final ResultSetMetaData metaData = rs.getMetaData();
// 总列数
final int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
// columnLabel代表as的值,columnName代表原名
// 默认取columnLabel的值
columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
// 每个字段对应的jdbc类型
jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
// 每个字段对应的java类型
classNames.add(metaData.getColumnClassName(i));
}
}
private void loadMappedAndUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {
List<String> mappedColumnNames = new ArrayList<>();
List<String> unmappedColumnNames = new ArrayList<>();
final String upperColumnPrefix = columnPrefix == null ? null : columnPrefix.toUpperCase(Locale.ENGLISH);
// resultMap已经手动定义映射的字段
final Set<String> mappedColumns = prependPrefixes(resultMap.getMappedColumns(), upperColumnPrefix);
for (String columnName : columnNames) {
final String upperColumnName = columnName.toUpperCase(Locale.ENGLISH);
if (mappedColumns.contains(upperColumnName)) {
mappedColumnNames.add(upperColumnName);
} else {
unmappedColumnNames.add(columnName);
}
}
mappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), mappedColumnNames);
unMappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), unmappedColumnNames);
}
// resultMap中已经映射的字段名
public List<String> getMappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {
List<String> mappedColumnNames = mappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));
if (mappedColumnNames == null) {
loadMappedAndUnmappedColumnNames(resultMap, columnPrefix);
mappedColumnNames = mappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));
}
return mappedColumnNames;
}
// resultMap中没有映射的字段名
public List<String> getUnmappedColumnNames(ResultMap resultMap, String columnPrefix) throws SQLException {
List<String> unMappedColumnNames = unMappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));
if (unMappedColumnNames == null) {
loadMappedAndUnmappedColumnNames(resultMap, columnPrefix);
unMappedColumnNames = unMappedColumnNamesMap.get(getMapKey(resultMap, columnPrefix));
}
return unMappedColumnNames;
}
}
1.2 ResultContext
public interface ResultContext<T> {
T getResultObject();
int getResultCount();
boolean isStopped();
void stop();
}
public class DefaultResultContext<T> implements ResultContext<T> {
/**
* 结果值
*/
private T resultObject;
/**
* 累计的结果数量
*/
private int resultCount;
/**
* 是否停止
*/
private boolean stopped;
public DefaultResultContext() {
resultObject = null;
resultCount = 0;
stopped = false;
}
@Override
public T getResultObject() {
return resultObject;
}
@Override
public int getResultCount() {
return resultCount;
}
@Override
public boolean isStopped() {
return stopped;
}
public void nextResultObject(T resultObject) {
resultCount++;
this.resultObject = resultObject;
}
@Override
public void stop() {
this.stopped = true;
}
}
1.3 ResultHandler
传入ResultContext,进行结果后置处理
public class DefaultResultHandler implements ResultHandler<Object> {
private final List<Object> list;
public DefaultResultHandler() {
list = new ArrayList<>();
}
@SuppressWarnings("unchecked")
public DefaultResultHandler(ObjectFactory objectFactory) {
list = objectFactory.create(List.class);
}
@Override
public void handleResult(ResultContext<?> context) {
// 就仅当结果存储
list.add(context.getResultObject());
}
public List<Object> getResultList() {
return list;
}
}
2 ResultMap结果集映射
映射是指返回的ResultSet列与Java Bean 属性之间的对应关系。通过ResultMapping进行映射描述,在用ResultMap封装成一个整体。
2.1 映射设置
一个ResultMap 中包含多个ResultMapping 表示一个具体的JAVA属性到列的映射,其主要值如下:
ResultMapping 有多种表现形式如下:
- constructor:构建参数字段
- id:ID字段
- result:普通结构集字段
- association:1对1关联字段
- Collection:1对多集合关联字段
2.2 自动映射
当前列名和属性名相同的情况下,可使用自动映射
自动映射条件
- 列名和属性名同时存在(勿略大小写,或者使用_拼接)
- 当前列未手动设置映射
- 属性类别存在TypeHandler
- 开启autoMapping (默认开启)
2.3 手动映射
mapper xml文件配置resultMap,其查询字段名称,存在resultMap中。blobWeb在resultMap中没有自定义手动映射,会采用自动映射赋值(开启autoMapping
)
<resultMap id="blogMap" type="com.scarecrow.mybatis.po.BlogPO">
<id column="id" property="id"/>
<result column="title" property="title"/>
</resultMap>
<select id="getBlogById" resultMap="blogMap">
select id, title, blobWeb
from tb_blog
where id = #{id,jdbcType=BIGINT}
</select>
3 handleResultSets 简单结果集映射
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
// 包装ResultSet
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
// 有结果集返回,没有ResultMap异常
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
// 处理当前结果集
handleResultSet(rsw, resultMap, multipleResults, null);
// 下一个结果集
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
// 多结果集情况,mapper.xml select设置resultSets
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
return collapseSingleResultList(multipleResults);
}
3.1 handleResultSet
根据ResultMap与ResultSet处理当前结果集
/**
* 构建出来的结果对象,如果父级结果属性映射不为null,会将结果对象赋值到父级结果属性对应的结果对象中,
* 否则将结果对象加入到reusltHandler中。最后从reusltHandler中取的最终的结果对象加入到多个结果
* 对象集合中
*
* @param rsw 结果集包装对象
* @param resultMap resultMap标签对象
* @param multipleResults 多个结果对象集合
* @param parentMapping 父级结果属性映射
* @throws SQLException
*/
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
try {
// 如果父级结果属性映射不为null
if (parentMapping != null) {
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else {
if (resultHandler == null) {
// 设置默认的resultHandler
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
// 构建出来的结果对象,如果父级结果属性映射不为null,会将结果对象赋值到父级结果属性对应的结果对象中,否则将结果对象加入到reusltHandler中
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
// 结果集每一行映射的对象加入最终返回的List中
multipleResults.add(defaultResultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// issue #228 (close resultsets)
closeResultSet(rsw.getResultSet());
}
}
3.2 handleRowValues
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
// 嵌套查询
if (resultMap.hasNestedResultMaps()) {
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
} else {
// 简单查询
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
3.3 handleRowValuesForSimpleResultMap
处理简单非嵌套结果集
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
// 新建一个默认的结果上下文
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
ResultSet resultSet = rsw.getResultSet();
// 查询结果集,跳过指定的行
skipRows(resultSet, rowBounds);
// 如果还有结果需要处理 而且 结果集还没有关闭 而且 结果集还有数据
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
// 逐层解析resultMap 鉴别器Discriminator,取得最终的ResultMap标签对象
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
//根据rsw 和resultMap 构建出对象
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
rs.absolute(rowBounds.getOffset());
}
} else {
for (int i = 0; i < rowBounds.getOffset(); i++) {
if (!rs.next()) {
break;
}
}
}
}
3.4 getRowValue
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
// 结果对象不为null 但没有对应结果类型的TypeHandler
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
3.5 createResultObject返回结果集对象
主要处理返回结果的对象有以下几种情况
-
返回结果类型有TypeHandler,会构造返回对象同时设置
返回值
-
返回结果类型与resultMap指定了constructor标签对应,resultMap会有constructorResultMappings。会根据constructor 找构造函数创建对象并设置构造函数参数的值
<resultMap id="resultMap" type="com.scarecrow.mybatis.po.UserPO"> <constructor> <arg column="USER_ID" javaType="long" jdbcType="DECIMAL"/> <arg column="USER_NAME" javaType="string" jdbcType="VARCHAR"/> </constructor> <result column="USER_ADDRESS" property="userAddress" jdbcType="VARCHAR"/> </resultMap>
-
返回结果类型是接口或者是存在无参的默认的构造函数
-
以上都不符合,开启了AutomaticMapping。根据构造函数来创建对象
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
this.useConstructorMappings = false; // reset previous mapping result
final List<Class<?>> constructorArgTypes = new ArrayList<>();
final List<Object> constructorArgs = new ArrayList<>();
// 取得构造函数所需的参数值去创建结果对象
Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
// 如果结果对象不为null但没有结果类型对应的TypeHandler
if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
// 获取属性结果映射关系集合,该集合不包括标记为构造函数的结果映射关系
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
for (ResultMapping propertyMapping : propertyMappings) {
// issue gcode #109 && issue #149
if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
break;
}
}
}
this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
return resultObject;
}
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
throws SQLException {
// 获取结果对象类型
final Class<?> resultType = resultMap.getType();
final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
// 获取构造函数映射关系
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
// 如果存在对应的TypeHandler
if (hasTypeHandlerForResultObject(rsw, resultType)) {
// 比如select只有一个字段count,resultMap的type为long。就会走这个分支。并且使用LongTypeHandler.getResult直接返回对象
return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
} else if (!constructorMappings.isEmpty()) {
// 根据构造函数映射构建的结果对象,部分字段会有值
return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
// 如果resultType是接口或者resultType有默认的无参构造函数
return objectFactory.create(resultType);
} else if (shouldApplyAutomaticMappings(resultMap, false)) {
// 是否可以应用自动映射。autoMapping:默认为null
// 根据构造函数的 参数类型自动映射
return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
}
throw new ExecutorException("Do not know how to create an instance of " + resultType);
}
3.5.1 返回结果类型有TypeHandler
这种情况一般只会返回一列
private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
final Class<?> resultType = resultMap.getType();
final String columnName;
if (!resultMap.getResultMappings().isEmpty()) {
final List<ResultMapping> resultMappingList = resultMap.getResultMappings();
final ResultMapping mapping = resultMappingList.get(0);
columnName = prependPrefix(mapping.getColumn(), columnPrefix);
} else {
columnName = rsw.getColumnNames().get(0);
}
final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
// 获取结果值
return typeHandler.getResult(rsw.getResultSet(), columnName);
}
3.5.2 resultMap指定了constructor标签
Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType, List<ResultMapping> constructorMappings,
List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) {
boolean foundValues = false;
// 遍历构造函数结果映射关系
for (ResultMapping constructorMapping : constructorMappings) {
// 获取构造函数参数映射关系对应java类型
final Class<?> parameterType = constructorMapping.getJavaType();
// 获取构造函数参数映射关系对应的列名
final String column = constructorMapping.getColumn();
final Object value;
try {
// 如果构造函数参数映射关系配置了嵌套查询的select标签ID
if (constructorMapping.getNestedQueryId() != null) {
value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
}
// 如果构造函数参数映射关系配置了嵌套的resultMapId
else if (constructorMapping.getNestedResultMapId() != null) {
final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
value = getRowValue(rsw, resultMap, getColumnPrefix(columnPrefix, constructorMapping));
}
// 不存在嵌套的情况
else {
// 获取构造函数参数映射的TypeHandler
final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
// 从ResultSet中取出columnName对应数据,然后转换为 java 对象
value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
}
} catch (ResultMapException | SQLException e) {
throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
}
// 将构造函数参数类型添加到constructorArgTypes中
constructorArgTypes.add(parameterType);
// 将构造函数参数对象添加到construtorArgs中
constructorArgs.add(value);
// 只要有一个构造函数参数对象不为null,foundValue都会为true
foundValues = value != null || foundValues;
}
// 利用反射根据构造参数类型获取 构造参数并创建对象
return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
}
3.5.3 无参构造函数
仅仅返回创建的对象
3.5.4 createByConstructorSignature
- 只有一个构造函数
- 多个构造函数使用了AutomapConstructor注解
会使用构造函数创建对象,并设置值(根据构造函数的参数)
private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) throws SQLException {
// 所有的构造函数
final Constructor<?>[] constructors = resultType.getDeclaredConstructors();
// 只有一个构造函数,或者多个构造函数中有AutomapConstructor 注解标识
final Constructor<?> defaultConstructor = findDefaultConstructor(constructors);
if (defaultConstructor != null) {
return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, defaultConstructor);
} else {
for (Constructor<?> constructor : constructors) {
// 构造函数的参数与返回列数一致
// 构造函数参数的数据类型与返回列的jdbcType匹配到 相应的TypeHandler
if (allowedConstructorUsingTypeHandlers(constructor, rsw.getJdbcTypes())) {
// 根据构造参数的个数与类型 创建返回对象
return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, constructor);
}
}
}
throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());
}
private Object createUsingConstructor(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor) throws SQLException {
boolean foundValues = false;
for (int i = 0; i < constructor.getParameterTypes().length; i++) {
// 构造参数字段类型
Class<?> parameterType = constructor.getParameterTypes()[i];
// 查询的字段,与参数顺序一致
String columnName = rsw.getColumnNames().get(i);
TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
constructorArgTypes.add(parameterType);
constructorArgs.add(value);
foundValues = value != null || foundValues;
}
return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
}
3.6 行结果集映射
getRowValue 主要包含两部分:
- 创建返回对象
- 为返回对象赋值
- 自动映射(查询的列没有 在resultMap指定)
- 手动映射(resultMap指定了查询的列)
3.6.1 自动映射
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
// 创建自动映射 AutomaticMappings
List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
boolean foundValues = false;
if (!autoMapping.isEmpty()) {
for (UnMappedColumnAutoMapping mapping : autoMapping) {
final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
if (value != null) {
foundValues = true;
}
if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
// gcode issue #377, call setter on nulls (value is not 'found')
metaObject.setValue(mapping.property, value);
}
}
}
return foundValues;
}
private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
final String mapKey = resultMap.getId() + ":" + columnPrefix;
List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
if (autoMapping == null) {
autoMapping = new ArrayList<>();
// 未映射的列
final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
for (String columnName : unmappedColumnNames) {
String propertyName = columnName;
if (columnPrefix != null && !columnPrefix.isEmpty()) {
// When columnPrefix is specified,
// ignore columns without the prefix.
if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
propertyName = columnName.substring(columnPrefix.length());
} else {
continue;
}
}
// 通过未映射的列,去获取javaBean相应的属性
final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
if (property != null && metaObject.hasSetter(property)) {
if (resultMap.getMappedProperties().contains(property)) {
continue;
}
// 通过未映射的列,去获取javaBean相应的属性类型
final Class<?> propertyType = metaObject.getSetterType(property);
if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {
final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
// 获取相应的 typeHandler
autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));
} else {
configuration.getAutoMappingUnknownColumnBehavior()
.doAction(mappedStatement, columnName, property, propertyType);
}
} else {
configuration.getAutoMappingUnknownColumnBehavior()
.doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null);
}
}
autoMappingsCache.put(mapKey, autoMapping);
}
return autoMapping;
}
3.6.2 手动映射
private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
throws SQLException {
final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
boolean foundValues = false;
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
for (ResultMapping propertyMapping : propertyMappings) {
String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
if (propertyMapping.getNestedResultMapId() != null) {
// the user added a column attribute to a nested result map, ignore it
column = null;
}
if (propertyMapping.isCompositeResult()
|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))
|| propertyMapping.getResultSet() != null) {
Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
// issue #541 make property optional
final String property = propertyMapping.getProperty();
if (property == null) {
continue;
} else if (value == DEFERRED) {
foundValues = true;
continue;
}
if (value != null) {
foundValues = true;
}
if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {
// gcode issue #377, call setter on nulls (value is not 'found')
// 反射设置属性值
metaObject.setValue(property, value);
}
}
}
return foundValues;
}
4. 嵌套查询
-
关联的嵌套 Select 查询
<resultMap id="blogResultNestedQuery" type="com.scarecrow.mybatis.po.BlogPO"> <id column="id" property="id"/> <result column="title" property="title"/> <result column="blobWeb" property="blobWeb"/> <association property="authorPO" javaType="com.scarecrow.mybatis.po.AuthorPO" column="id" select="selectAuthorNestedQuery"/> </resultMap> <resultMap id="authorResultNestedQuery" type="com.scarecrow.mybatis.po.AuthorPO"> <id column="id" property="id"/> <result column="username" property="username"/> <result column="email" property="email"/> </resultMap> <select id="selectBlogNestedQuery" resultMap="blogResultNestedQuery"> select id, title, blobWeb from tb_blog where id = #{id,jdbcType=BIGINT} </select> <select id="selectAuthorNestedQuery" resultMap="authorResultNestedQuery"> select id, username, email from tb_author where id = #{id,jdbcType=BIGINT} </select>
-
关联的嵌套结果映射
-
外部的嵌套结果映射
<resultMap id="blogAuthorNestedExternalMap" type="com.scarecrow.mybatis.po.BlogPO"> <id column="id" property="id"/> <result column="title" property="title"/> <result column="blobWeb" property="blobWeb"/> <association property="authorPO" javaType="com.scarecrow.mybatis.po.AuthorPO" resultMap="authorNestedExternalMap"/> </resultMap> <resultMap id="authorNestedExternalMap" type="com.scarecrow.mybatis.po.AuthorPO"> <id property="id" column="id" jdbcType="BIGINT"/> <result property="username" column="username" jdbcType="VARCHAR"/> <result property="email" column="email" jdbcType="VARCHAR"/> </resultMap> <select id="getBlogAndAuthorExternal" resultMap="blogAuthorNestedExternalMap"> select b.id, b.title, b.blobWeb, a.id, a.username, a.email from tb_blog b, tb_author a where b.id = a.blog_id and b.id = #{id,jdbcType=BIGINT} </select>
-
内部嵌套结果映射
<!--嵌套结果映射--> <resultMap id="blogAuthorNestedResultsMap" type="com.scarecrow.mybatis.po.BlogPO"> <id column="id" property="id"/> <result column="title" property="title"/> <result column="blobWeb" property="blobWeb"/> <association property="authorPO" javaType="com.scarecrow.mybatis.po.AuthorPO"> <id property="id" column="id" jdbcType="BIGINT"/> <result property="username" column="username" jdbcType="VARCHAR"/> <result property="email" column="email" jdbcType="VARCHAR"/> </association> </resultMap> <select id="getBlogAndAuthorNestedResultsById" resultMap="blogAuthorNestedResultsMap"> select b.id, b.title, b.blobWeb, a.id, a.username, a.email from tb_blog b, tb_author a where b.id = a.blog_id and b.id = #{id,jdbcType=BIGINT} </select>
-
4.1 嵌套结果映射
4.1.1 嵌套结果映射xml解析
解析xml文件中的resultMap时会解析嵌套查询与嵌套结果集映射
// 嵌套结果映射
private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings, Class<?> enclosingType) {
if (Arrays.asList("association", "collection", "case").contains(context.getName())
&& context.getStringAttribute("select") == null) {
validateCollection(context, enclosingType);
// 解析内部的嵌套的ResultMap
ResultMap resultMap = resultMapElement(context, resultMappings, enclosingType);
return resultMap.getId();
}
return null;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DFBx9eiX-1635085902946)(…/…/AppData/Roaming/Typora/typora-user-images/image-20210928222841111.png)]
4.1.2 嵌套结果集映射
4.2关联的嵌套 Select 查询
from tb_blog b, tb_author a
where b.id = a.blog_id
and b.id = #{id,jdbcType=BIGINT}
```
4.1 嵌套结果映射
4.1.1 嵌套结果映射xml解析
解析xml文件中的resultMap时会解析嵌套查询与嵌套结果集映射
[外链图片转存中…(img-QxoQCsjR-1635085902945)]
// 嵌套结果映射
private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings, Class<?> enclosingType) {
if (Arrays.asList("association", "collection", "case").contains(context.getName())
&& context.getStringAttribute("select") == null) {
validateCollection(context, enclosingType);
// 解析内部的嵌套的ResultMap
ResultMap resultMap = resultMapElement(context, resultMappings, enclosingType);
return resultMap.getId();
}
return null;
}
[外链图片转存中…(img-DFBx9eiX-1635085902946)]