Java Bean中某些屬性沒有在<resultMap/>做配置的時(shí)候利用<result/>做映射惫东,在做最后結(jié)果映射的時(shí)候是否會(huì)將這些"某些屬性"設(shè)置值?autoMapping就是一個(gè)用來決定是否設(shè)置這些"某些屬性"的一個(gè)開關(guān)颓遏。
mybatis pom
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.0</version>
</dependency>
autoMapping用法
代碼片段
<settings>
<!-- 打印查詢語句 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 配置駝峰轉(zhuǎn)下劃線 數(shù)據(jù)庫中的下劃線叁幢,轉(zhuǎn)換Java Bean中的駝峰-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<resultMap id="ModelMapper" type="mybatis.entity.ModelEntity" autoMapping="false">
<result column="id" property="id"/>
</resultMap>
<resultMap id="ModelMapper" type="mybatis.entity.ModelEntity" autoMapping="true">
<result column="id" property="id"/>
</resultMap>
<select id="selectAll" resultMap="ModelMapper">
<!-- There is no getter for property named 'value111111' in 'class java.lang.String' -->
select * from model
</select>
public class ModelEntity {
private Integer id;
private String modelName;
private String modelCode;
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[id = ");
sb.append(id);
sb.append(", modelName = ");
sb.append(modelName);
sb.append(", modelCode = ");
sb.append(modelCode);
sb.append("]");
return sb.toString();
}
}
- 如果設(shè)置 autoMapping="false"曼玩,那么獲得到的實(shí)體為:[id = 1, modelName = null, modelCode = null]
- 如果設(shè)置 autoMapping="true"窒百,那么獲得到的實(shí)體為:[id = 1, modelName = model1, modelCode = code1]
<resultMap/>屬性autoMapping的裝配
- 配置文件中配置了<resultMap/>篙梢,配置了就讀取沒有配置就是null了;
// XMLMapperBuilder#resultMapElement
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception {
...
Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
...
}
- 配置文件中并沒有配置<resultMap/>,且在<select/>中的返回值用了type屬性
這種情況會(huì)在解析<select/>創(chuàng)建一個(gè)in-line ResultMap渤滞,這時(shí)ResultMap#autoMapping = null
private void setStatementResultMap(
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
MappedStatement.Builder statementBuilder) {
if (resultMap != null) {
...
} else if (resultType != null) {
ResultMap.Builder inlineResultMapBuilder = new ResultMap.Builder(
configuration,
statementBuilder.id() + "-Inline",
resultType,
new ArrayList<ResultMapping>(),
null); // 可以看到傳入的autoMapping = null
resultMaps.add(inlineResultMapBuilder.build());
}
}
查詢結(jié)果是否會(huì)自動(dòng)映射
在做結(jié)果映射的時(shí)候是否會(huì)做自動(dòng)映射取決于以下兩個(gè)方面:
- 是否設(shè)置<resultMap/>屬性autoMapping蔼水,默認(rèn)ResultMap#autoMapping = null
- 是否配置了autoMappingBehavior這個(gè)全局屬性,Configuration#autoMappingBehavior默認(rèn)是AutoMappingBehavior.PARTIAL;
下面是相關(guān)代碼片段:
// DefaultResultSetHandler#shouldApplyAutomaticMappings
private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
if (resultMap.getAutoMapping() != null) {
return resultMap.getAutoMapping();
} else {
if (isNested) {
return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();
} else {
// Configuration#autoMappingBehavior默認(rèn)是AutoMappingBehavior.PARTIAL;
return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();
}
}
}
public enum AutoMappingBehavior {
// 禁止所有的自動(dòng)映射
NONE,
// 只有在<resultMap/>沒有嵌套的ResultMap時(shí)生效
PARTIAL,
// 任何情況下都會(huì)生效
FULL
}
總結(jié)為以下3點(diǎn)
- 配置autoMapping=true會(huì)做自動(dòng)映射吊说;
- 配置autoMapping=false不會(huì)做自動(dòng)映射颁井;
- 沒有做autoMapping配置也沒有做autoMappingBehavior配置,默認(rèn)對(duì)于沒有嵌套的<resultMap/>會(huì)做自動(dòng)映射养涮,對(duì)于有嵌套的<resultMap/>不會(huì)做自動(dòng)映射眉抬。
查詢結(jié)果自動(dòng)映射源碼
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
// 自動(dòng)映射只會(huì)映射ResultMap沒有的屬性蜀变,即該屬性沒有對(duì)應(yīng)的ResultMapping
// 處理很簡(jiǎn)單 ResultSet對(duì)應(yīng)的所有column - <resultMap/> 已經(jīng)映射的屬性
final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
boolean foundValues = false;
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;
}
}
// 找到column對(duì)應(yīng)的property库北,如果沒有找到就不會(huì)做映射,這里還有一個(gè)屬性時(shí)下劃線轉(zhuǎn)駝峰
// 這里下劃線轉(zhuǎn)駝峰并沒有做字符串拼接情屹,很粗糙的一種杂腰,就是去掉propertyName中所有下劃線颈墅,
// 然后用大小寫不敏感的方式去map中找到該列對(duì)應(yīng)的屬性名,具體參見Reflector#findPropertyName恤筛。
// 這種粗糙的寫法有一個(gè)前提毒坛,數(shù)據(jù)庫中所有字符和Java Bean中屬性名的所有字母一樣煎殷,如果拼寫錯(cuò)誤很有可能
// 會(huì)找不到豪直。
final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
if (property != null && metaObject.hasSetter(property)) {
final Class<?> propertyType = metaObject.getSetterType(property);
if (typeHandlerRegistry.hasTypeHandler(propertyType)) {
final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
final Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
// issue #377, call setter on nulls
if (value != null || configuration.isCallSettersOnNulls()) {
// 如果value是null且當(dāng)前屬性對(duì)應(yīng)的類是原始實(shí)行珠移,不設(shè)置值末融,因?yàn)樵O(shè)置不了為null
if (value != null || !propertyType.isPrimitive()) {
metaObject.setValue(property, value);
}
foundValues = true;
}
}
}
}
return foundValues;
}