resultMap 元素是 MyBatis 中最重要最强大的元素。它就是让你远离 90%的需要从结果集中取出数据的 JDBC 代码的那个东西,而且在一些情形下允许你做一些 JDBC 不支持的事情。事实上,编写相似于对复杂语句联合映射这些等同的代码,也许可以跨过上千行的代码。

ResultMap 的设计就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们的关系。

你已经看到简单映射语句的示例了,但没有明确的 resultMap。比如:

<select id=”selectUsers” parameterType=”int” resultType=”hashmap”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>

这样一个语句简单作用于所有列被自动映射到 HashMap 的键上,这由resultType 属性指定。这在很多情况下是有用的,但是 HashMap 不能很好描述一个领域模型。那样你的应用程序将会使用 JavaBeans 或 POJOs来作为领域模型。MyBatis 对两者都支持。看看下面这个 JavaBean:

package com.someapp.model;
public class User {private int id;private String username;private String hashedPassword;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getHashedPassword() {return hashedPassword;}public void setHashedPassword(String hashedPassword) {this.hashedPassword = hashedPassword;}
}

基于 JavaBean 的规范,上面这个类有 3 个属性:id,username 和hashedPassword。这些在 select 语句中会精确匹配到列名。这样的一个 JavaBean 可以被映射到结果集,就像映射到 HashMap 一样简单。

<select id=”selectUsers” parameterType=”int”
resultType=”com.someapp.model.User”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>

要记住类型别名是你的伙伴。使用它们你可以不用输入类的全路径。比如:

<!-- 在XML配置文件中-->
<typeAlias type=”com.someapp.model.User” alias=”User”/>
<!-- 在SQL映射的XML文件中-->
<select id=”selectUsers” parameterType=”int”
resultType=”User”>
select id, username, hashedPassword
from some_table
where id = #{id}
</select>

这些情况下,MyBatis 会在幕后自动创建一个 ResultMap,基于属性名来映射列到JavaBean 的属性上。如果列名没有精确匹配,你可以在列名上使用 select 字句的别名(一个标准的 SQL 特性)来匹配标签。比如:

<select id=”selectUsers” parameterType=”int” resultType=”User”>
select
user_id as “id”,
user_name as “userName”,
hashed_password as “hashedPassword”
from some_table
where id = #{id}
</select>

那么如何试用外部的 resultMap:

<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>

引用它的语句使用 resultMap 属性就行了(注意我们去掉了 resultType 属性)。比如:

<select id=”selectUsers” parameterType=”int”
resultMap=”userResultMap”>
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>

ReulstMap只是字段与属性之间的映射关系的集合,那么,真正的字段与属性之间的映射关系,ResultMapping(org.apache.ibatis.mapping.ResultMapping)属性映射来描述。

ResultMap数据结构如下:

package org.apache.ibatis.mapping;import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;import org.apache.ibatis.session.Configuration;/*** 结果映射,保存着表与对象之间的映射关系**/
public class ResultMap {// 对应<resultMap>的id属性private String id;// 对应<resultMap>的type属性private Class<?> type;// 对应除<discriminator>元素外的所有属性映射关系private List<ResultMapping> resultMappings;// 对应所有属性映射中带有ID标志的映射关系,包括<id>元素和<constructor>的<idArg>子元素private List<ResultMapping> idResultMappings;// 对应所有属性映射中带有Constructor标志的映射关系,包括<constructor>所有子元素private List<ResultMapping> constructorResultMappings;// 对应所有属性映射中不带有Constructor标志的映射关系private List<ResultMapping> propertyResultMappings;// 对应所有属性映射中的column属性的集合private Set<String> mappedColumns;// 鉴别器,对应<discriminator>元素private Discriminator discriminator;// 是否含有嵌套的结果映射,// 如果某个属性映射存在resultMap属性,且不存在resultSet属性,则为trueprivate boolean hasNestedResultMaps;// 是否含有嵌套查询,// 如果某个属性映射存在select属性,则为trueprivate boolean hasNestedQueries;// 是否开启自动映射private Boolean autoMapping;
}

而且在ResultMap类内部有一个静态的构造类,如下:

  //静态内部类,建造者模式public static class Builder {private ResultMapping resultMapping = new ResultMapping();public Builder(Configuration configuration, String property, String column, TypeHandler<?> typeHandler) {this(configuration, property);resultMapping.column = column;resultMapping.typeHandler = typeHandler;}public Builder(Configuration configuration, String property, String column, Class<?> javaType) {this(configuration, property);resultMapping.column = column;resultMapping.javaType = javaType;}public Builder(Configuration configuration, String property) {resultMapping.configuration = configuration;resultMapping.property = property;resultMapping.flags = new ArrayList<ResultFlag>();resultMapping.composites = new ArrayList<ResultMapping>();resultMapping.lazy = configuration.isLazyLoadingEnabled();}public Builder javaType(Class<?> javaType) {resultMapping.javaType = javaType;return this;}public Builder jdbcType(JdbcType jdbcType) {resultMapping.jdbcType = jdbcType;return this;}public Builder nestedResultMapId(String nestedResultMapId) {resultMapping.nestedResultMapId = nestedResultMapId;return this;}public Builder nestedQueryId(String nestedQueryId) {resultMapping.nestedQueryId = nestedQueryId;return this;}public Builder resultSet(String resultSet) {resultMapping.resultSet = resultSet;return this;}public Builder foreignColumn(String foreignColumn) {resultMapping.foreignColumn = foreignColumn;return this;}public Builder notNullColumns(Set<String> notNullColumns) {resultMapping.notNullColumns = notNullColumns;return this;}public Builder columnPrefix(String columnPrefix) {resultMapping.columnPrefix = columnPrefix;return this;}public Builder flags(List<ResultFlag> flags) {resultMapping.flags = flags;return this;}public Builder typeHandler(TypeHandler<?> typeHandler) {resultMapping.typeHandler = typeHandler;return this;}public Builder composites(List<ResultMapping> composites) {resultMapping.composites = composites;return this;}public Builder lazy(boolean lazy) {resultMapping.lazy = lazy;return this;}public ResultMapping build() {// lock down collectionsresultMapping.flags = Collections.unmodifiableList(resultMapping.flags);resultMapping.composites = Collections.unmodifiableList(resultMapping.composites);resolveTypeHandler();validate();return resultMapping;}//一些验证逻辑,验证result map有没有写错private void validate() {// Issue #697: cannot define both nestedQueryId and nestedResultMapIdif (resultMapping.nestedQueryId != null && resultMapping.nestedResultMapId != null) {throw new IllegalStateException("Cannot define both nestedQueryId and nestedResultMapId in property " + resultMapping.property);}// Issue #5: there should be no mappings without typehandlerif (resultMapping.nestedQueryId == null && resultMapping.nestedResultMapId == null && resultMapping.typeHandler == null) {throw new IllegalStateException("No typehandler found for property " + resultMapping.property);}// Issue #4 and GH #39: column is optional only in nested resultmaps but not in the restif (resultMapping.nestedResultMapId == null && resultMapping.column == null && resultMapping.composites.isEmpty()) {throw new IllegalStateException("Mapping is missing column attribute for property " + resultMapping.property);}if (resultMapping.getResultSet() != null) {int numColums = 0;if (resultMapping.column != null) {numColums = resultMapping.column.split(",").length;}int numForeignColumns = 0;if (resultMapping.foreignColumn != null) {numForeignColumns = resultMapping.foreignColumn.split(",").length;}if (numColums != numForeignColumns) {throw new IllegalStateException("There should be the same number of columns and foreignColumns in property " + resultMapping.property);}}}private void resolveTypeHandler() {if (resultMapping.typeHandler == null && resultMapping.javaType != null) {Configuration configuration = resultMapping.configuration;TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();resultMapping.typeHandler = typeHandlerRegistry.getTypeHandler(resultMapping.javaType, resultMapping.jdbcType);}}public Builder column(String column) {resultMapping.column = column;return this;}}

ResultMapping数据结构如下:

package org.apache.ibatis.mapping;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;/*** 字段映射 一个ResultMapping实例对应ResultSet中一个字段到javaBean中一个属性的映射关系* * sql元素中,除了<discriminator>子元素以外的其他元素都会生成此类型实例,* 其中包括:* <idArg><arg><id><result><association><collection>* * 内部包含Builder类,负责数据的整合和校验,不负责传入参数的解析* @author Administrator**/
public class ResultMapping {// 核心配置对象private Configuration configuration;// 属性名,对应元素的property属性private String property;// 字段名,对应元素的column属性private String column;// 属性的java类型,对应元素的javaType属性private Class<?> javaType;// 字段的jdbc类型,对应元素的jdbcType属性private JdbcType jdbcType;// 类型处理器,对应元素的typeHandler属性private TypeHandler<?> typeHandler;// 对应元素的resultMap属性应用名称空间后的结果private String nestedResultMapId;// 对应元素的select属性应用名称空间后的结果private String nestedQueryId;// 对应元素的notNullColumn属性拆分后的结果private Set<String> notNullColumns;// 对应元素的columnPrefix属性private String columnPrefix;// 处理后的标志,标志共两个:id和constructorprivate List<ResultFlag> flags;// 对应元素的column属性拆分后生成的结果,composites.size()>0会时column为nullprivate List<ResultMapping> composites;// 对应元素的resultSet属性private String resultSet;// 对应元素的foreignColumn属性private String foreignColumn;// 是否延迟加载,对应元素的fetchType属性值,lazy则为true否则为false// 也直接从配置对象中读取private boolean lazy;
}

转载于:https://blog.51cto.com/manunited1985/2047808

04. Mybatis的resultMap基本应用相关推荐

  1. Mybatis的ResultMap的使用

    本篇文章通过一个实际工作中遇到的例子开始吧: 工程使用Spring+Mybatis+Mysql开发.具体的业务逻辑很重,对象之间一层一层的嵌套.和数据库表对应的是大量的model类,而和前端交互的是V ...

  2. 使用mybatis的resultMap进行复杂查询

    记录下mybatis的集合查询中碰到的问题 https://jaychang.iteye.com/blog/2357143 MyBatis ofType和javaType区别 https://blog ...

  3. mybatis的resultMap配置详解

    1.mybatis的实体类继承 参考资料: 1.mybatis中实体类,po类继承另一个po类的情况 2.mybatis中resultMap配置细则 实体类的继承的作用是:可以通过继承减少代码在实体类 ...

  4. MyBatis中resultMap详解

    MyBatis 中 resultMap 详解 resultMap 是 Mybatis 最强大的元素之一,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中.如在实际应用中,有一个表 ...

  5. 【MyBatis】resultMap和resultType的区别

    mybatis中resultMap和resultType的区别 mybatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap.resultType是 ...

  6. mybatis 使用resultMap实现数据库的操作

    resultType:直接表示返回类型 resultMap:对外部resultMap的引用 二者不能同时使用 创建一个实体类Role和User public class Role {private I ...

  7. Mybatis:resultMap的万字使用总结

    结果映射(resultMap) resultMap 元素是 MyBatis 中最重要最强大的元素.它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你 ...

  8. mybatis 使用in 查询时报错_使用mybatis的resultMap进行复杂查询 057

    拿到表的第一时间要学会分析陌生表的数据模型: 1.学习单表记录了什么东西(去学习理解需求) 2.学习单表重要字段的意义(优先学习不能为空的字段) 3.学习表与表之间的关系(一对一.一对多.多对多)通过 ...

  9. MyBatis使用resultMap自定义映射规则与关联映射

    一.写在前面 在MyBatis 的全局配置文件中我们可以通过在settings标签中设置 <setting name="mapUnderscoreToCamelCase" v ...

最新文章

  1. 中科院微生物所王军课题组建立靶向RNA的病原检测新方法mtNGS和mtTGS
  2. COM线程模型的行为
  3. EL表达式和JSTL
  4. S3C6410的Bootloader的两个阶段BL1和BL2编译相关学习
  5. GO标准库—命令行参数解析FLAG
  6. 前端面试题及答案整理(一)
  7. 非域环境下使用证书部署数据库(SqlServer2008R2)镜像
  8. Java,使用泛型构建自己的工具包——包装System.out
  9. python和控制流程_Python基础之:Python中的流程控制
  10. va_start(),va_end()函数应用
  11. Linux下安装Apache Maven安装
  12. Pollard_rho大数质因数分解+拉格朗日四平方和定理(bzoj 2904: 平方和)
  13. MFC在指定控件区域内进行一些操作
  14. python turtle库下载_win10+python3.8安装turtle库
  15. Android应用开发入门教程(经典版)
  16. Mob 的分享的集成
  17. 一款批量修改AE模板的工具
  18. ftw遍历目录树 getcwd取得当前的工作目录
  19. 微信小程序tarBar使用
  20. python调用DLL/EXE文件截屏的比较

热门文章

  1. c#退出窗口跳转_关于winform如何如在关闭一个窗口时打开另外一个窗口
  2. python 博弈论 库_SHAP:Python的可解释机器学习库
  3. Logback日志配置(分级别输出到不同文件)
  4. startsWith(),endsWith()的作用,用法,判断字符串a 是不是以字符串b开头或结尾
  5. matlab选择激发波长,【求助】怎么确定一个物质的激发波长和发射波长?
  6. mysql类型_MySQL的数据类型
  7. 电路过孔温度没有我们想象的那么高
  8. 2021年春季学期-信号与系统-第十四次作业参考答案-第七小题参考答案
  9. 交流线圈磁芯上的短路铜片
  10. 第十五届全国大学生智能汽车竞赛 信标组亮灯顺序和次数