7 Mybatis结果集自动映射
在使用Mybatis时,有的时候我们可以不用定义resultMap,而是直接在<select>语句上指定resultType。这个时候其实就用到了Mybatis的结果集自动映射。Mybatis的自动映射默认是开启的,其在映射的时候会先把没有在resultMap中定义字段映射的字段按照名称相同的方式自动映射到返回类型的对应属性上。自动映射的时候会忽略大小写,比如查询语句中查询出来了一个字段是ID,我们对应的返回类型有一个属性id,且有一个setId()方法,那么id跟ID也是可以匹配的,是可以自动映射的,Mybatis就会把查询出来的结果集中字段ID对应的值赋给返回类型对象的id属性。
7.1 源码分析
关于自动映射这块的逻辑规则可以参考Mybatis的DefaultResultSetHandler的源码,其核心代码如下。
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
List<UnMappedColumAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
boolean foundValues = false;
if (autoMapping.size() > 0) {
for (UnMappedColumAutoMapping mapping : autoMapping) {
final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
if (value != null || configuration.isCallSettersOnNulls()) {
if (value != null || !mapping.primitive) {
metaObject.setValue(mapping.property, value);
}
foundValues = true;
}
}
}
return foundValues;
}
private List<UnMappedColumAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
final String mapKey = resultMap.getId() + ":" + columnPrefix;
List<UnMappedColumAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
if (autoMapping == null) {
autoMapping = new ArrayList<UnMappedColumAutoMapping>();
final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
for (String columnName : unmappedColumnNames) {
String propertyName = columnName;
if (columnPrefix != null && !columnPrefix.isEmpty()) {
if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
propertyName = columnName.substring(columnPrefix.length());
} else {
continue;
}
}
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);
autoMapping.add(new UnMappedColumAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));
}
}
}
autoMappingsCache.put(mapKey, autoMapping);
}
return autoMapping;
}
在上面的源码中createAutomaticMappings()方法中的下面这句就是获取当前查询结果集中没有在resultMap中映射的字段,以进行自动映射。详情请参考完整的源码。
final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
7.2 示例
现假设我们有一个User类,其有id、name、username、email、mobile属性,然后有下面这样一个查询及其对应的resultMap定义。我们可以看到我们查询出来的有id、name、user_name、email和mobile字段,在resultMap中我们只配置了字段user_name对应的是username属性,其它的我们都没配置,但是查询出来的结果中User对象的id、name、username、email和mobile属性都会有值,因为它们会被Mybatis以自动映射策略进行赋值。
<resultMap type="com.elim.learn.mybatis.model.User" id="BaseResult">
<result column="user_name" property="username"/>
</resultMap>
<select id="findById" resultMap="BaseResult" parameterType="java.lang.Long" >
select id,name,username user_name,email,mobile from t_user where id=#{id}
</select>
7.3 自动映射策略
Mybatis的自动映射策略默认是开启的,而且默认是只对非嵌套的resultMap进行自动映射。这是通过Mybatis的全局配置autoMappingBehavior参数配置的。它一共有三种取值,分别是NONE、PARTIAL和FULL。
l NONE表示不启用自动映射
l PARTIAL表示只对非嵌套的resultMap进行自动映射
l FULL表示对所有的resultMap都进行自动映射
<!-- 自动映射类型,可选值为NONE、PARTIAL和FULL,参考AutoMappingBehavior枚举 -->
<setting name="autoMappingBehavior" value="PARTIAL"/>
除了全局的是否启用自动映射的配置外,还可以对特定的resultMap设置是否启用自动映射。这是通过resultMap的autoMapping属性配置的,可选值是true和false。定义在resultMap上的autoMapping的优先级比全局配置的优先级更高。
7.4 resultType自动映射分析
我们在指定一个查询语句的返回结果时,可以直接指定resultType,也可以是指定resultMap,然后由指定的resultMap的type属性指定真实的返回类型。实际上,Mybatis的底层在对结果集进行处理时都是通过resultMap进行处理的。当我们指定的是resultType时,Mybatis内部会生成一个空的resultMap,然后指定其对应的type为我们指定的resultType类型。那这个时候之所以返回结果能自动映射到resultType类型的对应属性上,就是上面介绍的Mybatis的自动映射机制的作用。如果在这种情况下,我们把全局的自动映射关闭了,那么Mybatis就不能自动映射了,也就得不到我们需要的返回结果了。如下就是直接指定的resultType。
<select id="findById" resultType="com.elim.learn.mybatis.model.User" parameterType="java.lang.Long" >
select id,name,username,email,mobile from t_user where id=#{id}
</select>
Mybatis的mapper.xml文件的内容是由XMLMapperBuilder解析的,而其中定义的Mapper语句(select、insert等)则是由XMLStatementBuilder解析的,解析后会生成一个MappedStatement。对于Select语句,其对应的resultMap的解析的核心逻辑如下,更多信息请参考官方源码。
private List<ResultMap> getStatementResultMaps(
String resultMap,
Class<?> resultType,
String statementId) {
resultMap = applyCurrentNamespace(resultMap, true);
List<ResultMap> resultMaps = new ArrayList<ResultMap>();
if (resultMap != null) {
String[] resultMapNames = resultMap.split(",");
for (String resultMapName : resultMapNames) {
try {
resultMaps.add(configuration.getResultMap(resultMapName.trim()));
} catch (IllegalArgumentException e) {
throw new IncompleteElementException("Could not find result map " + resultMapName, e);
}
}
} else if (resultType != null) {
ResultMap inlineResultMap = new ResultMap.Builder(
configuration,
statementId + "-Inline",
resultType,
new ArrayList<ResultMapping>(),
null).build();
resultMaps.add(inlineResultMap);
}
return resultMaps;
}
7.5 参考文档
官方源码
(注:本文是基于Mybatis3.3.1所写,写于2016年12月28日星期三)
相关推荐
下面我们将深入探讨Mybatis结果集自动映射的原理及实例代码。 自动映射主要依赖于以下两个条件: 1. `resultType`:在SQL查询的`<select>`标签中,设置`resultType`属性为对应的Java类全限定名。这告诉Mybatis查询...
4. Service和DAO层:在Service层中调用DAO层的方法,执行查询SQL,MyBatis会自动将结果按照映射关系进行装配。 三、注解方式的一对多映射 使用注解的方式也可以实现一对多映射,主要使用`@One`和`@Many`注解。`@One...
在Mybatis中,自动映射工具——Mybatis Generator(MBG)是一个非常实用的功能,它可以自动生成映射文件,包括XML配置文件和对应的Java实体类,从而减轻了开发人员的工作负担。 Mybatis Generator(MBG)是Mybatis...
MyBatis 的自动映射是基于注解或 XML 配置文件实现的,它能够在执行 SQL 查询后,自动将结果集与 Java 对象进行映射。例如,当我们在实体类中定义了与数据库表字段对应的属性,并在 SQL 映射文件中设置了 `...
MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 映射...
2. 映射文件与 XML 映射元素:Mybatis 的映射文件通常以 `.xml` 结尾,如 `mybatis3.xml`,它包含了 SQL 语句和结果集映射。在映射文件中,`<select>`, `<insert>`, `<update>`, `<delete>` 元素分别对应 SQL 的查询...
此外,Mybatis提供了自动映射功能,即无需显式定义每个字段的映射关系,它会尝试根据Java字段名与数据库列名的匹配规则进行自动映射。但这并不总是可行,特别是当列名与字段名不一致时,此时就需要自定义结果映射。 ...
MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解进行配置和原始映射,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java 对象)映射成数据库中的...
MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 2. **...
2. Mapping(映射文件):XML格式的文件,定义了SQL语句和结果集映射。在mapping文件中,我们可以编写动态SQL,实现复杂的查询逻辑。 3. Entity(实体类):表示数据库表中的记录,每个字段对应表中的一个列。实体...
Mybatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射,避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。在本项目中,我们看到一个名为"MpGenerator.java"的文件,这通常是一个代码生成...
Mybatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。它将关注点集中在SQL语句上,使得数据库操作更加直观和易于维护。Mybatis的核心是基于XML或注解的映射文件,它将数据库表与Java对象进行绑定,使得...
复杂映射开发是Mybatis框架中的一个重要部分,它支持将单个结果集映射到复杂类型的嵌套结构中。 首先,Mybatis的复杂映射通过自定义映射规则来实现,如XML配置文件中可以定义多种映射类型和行为。在自定义映射中,`...
1. **MyBatis映射文件(XML)**:MyBatis的核心之一是XML映射文件,它定义了SQL语句、参数和结果集的映射。XML映射文件通常位于项目的resources目录下,通过这些文件,开发者可以灵活地编写复杂的SQL语句并与Java...
而MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射,避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。本篇主要讨论如何利用Maven来自动化生成MyBatis的映射文件。 一、MyBatis ...
Mybatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。Mybatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 接下来...
Mybatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。Mybatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 接下来...
MyBatis映射文件生成工具是一款实用的开发辅助软件,主要功能是自动生成MyBatis的映射文件(Mapper XML文件),从而极大地提高了开发效率,减轻了开发人员手动编写SQL和映射语句的工作负担。在数据库表结构发生变化...
每个Mapper接口对应一个XML映射文件,其中包含SQL语句及其结果集映射。XML映射文件通常放在`resources`目录下的`mapper`子目录中,例如`UserMapper.xml`。在XML文件中,我们可以定义`select`、`insert`、`update`和`...
MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 自动...