Mybatis结果集自动映射

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 7       Mybatis结果集自动映射          在使用Mybatis时,有的时候我们可以不用定义resultMap,而是直接在语句上指定resultType。这个时候其实就用到了Mybatis的结果集自动映射。

7       Mybatis结果集自动映射

 

       在使用Mybatis时,有的时候我们可以不用定义resultMap,而是直接在<select>语句上指定resultType。这个时候其实就用到了Mybatis的结果集自动映射。Mybatis的自动映射默认是开启的,其在映射的时候会先把没有在resultMap中定义字段映射的字段按照名称相同的方式自动映射到返回类型的对应属性上。自动映射的时候会忽略大小写,比如查询语句中查询出来了一个字段是ID,我们对应的返回类型有一个属性id,且有一个setId()方法,那么idID也是可以匹配的,是可以自动映射的,Mybatis就会把查询出来的结果集中字段ID对应的值赋给返回类型对象的id属性。

 

7.1     源码分析

       关于自动映射这块的逻辑规则可以参考MybatisDefaultResultSetHandler的源码,其核心代码如下。

  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类,其有idnameusernameemailmobile属性,然后有下面这样一个查询及其对应的resultMap定义。我们可以看到我们查询出来的有idnameuser_nameemailmobile字段,在resultMap中我们只配置了字段user_name对应的是username属性,其它的我们都没配置,但是查询出来的结果中User对象的idnameusernameemailmobile属性都会有值,因为它们会被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参数配置的。它一共有三种取值,分别是NONEPARTIALFULL

l  NONE表示不启用自动映射

l  PARTIAL表示只对非嵌套的resultMap进行自动映射

l  FULL表示对所有的resultMap都进行自动映射

 

      <!-- 自动映射类型,可选值为NONEPARTIALFULL,参考AutoMappingBehavior枚举 -->

      <setting name="autoMappingBehavior" value="PARTIAL"/>

 

       除了全局的是否启用自动映射的配置外,还可以对特定的resultMap设置是否启用自动映射。这是通过resultMapautoMapping属性配置的,可选值是truefalse。定义在resultMap上的autoMapping的优先级比全局配置的优先级更高。

 

7.4     resultType自动映射分析

       我们在指定一个查询语句的返回结果时,可以直接指定resultType,也可以是指定resultMap,然后由指定的resultMaptype属性指定真实的返回类型。实际上,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>

 

       Mybatismapper.xml文件的内容是由XMLMapperBuilder解析的,而其中定义的Mapper语句(selectinsert等)则是由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所写,写于20161228日星期三)

 

 

目录
相关文章
|
1月前
|
SQL XML Java
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
文章介绍了MyBatis中高级查询的一对多和多对一映射处理,包括创建数据库表、抽象对应的实体类、使用resultMap中的association和collection标签进行映射处理,以及如何实现级联查询和分步查询。此外,还补充了延迟加载的设置和用法。
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
|
3月前
|
SQL Java 数据库连接
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
74 3
|
4月前
|
SQL XML Java
后端数据库开发JDBC编程Mybatis之用基于XML文件的方式映射SQL语句实操
后端数据库开发JDBC编程Mybatis之用基于XML文件的方式映射SQL语句实操
67 3
若依修改,集成mybatisplus报错,若依集成mybatisplus,总是找不到映射是怎么回事只要是用mp的方法就找报,改成mybatisPlus配置一定要改
若依修改,集成mybatisplus报错,若依集成mybatisplus,总是找不到映射是怎么回事只要是用mp的方法就找报,改成mybatisPlus配置一定要改
|
5月前
|
SQL Java 数据库连接
【Mybatis】深入学习MyBatis:概述、主要特性以及配置与映射
【Mybatis】深入学习MyBatis:概述、主要特性以及配置与映射
【Mybatis】深入学习MyBatis:概述、主要特性以及配置与映射
|
5月前
|
算法 BI 数据库
MyBatisPlus查询条件设置、映射匹配兼容性、id生成策略、多数据操作
MyBatisPlus查询条件设置、映射匹配兼容性、id生成策略、多数据操作
318 3
|
5月前
|
SQL Java 数据库连接
15:MyBatis对象关系与映射结构-Java Spring
15:MyBatis对象关系与映射结构-Java Spring
104 4
|
10天前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
36 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
10天前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
22 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
17天前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
136 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个