千家信息网

04. Mybatis的resultMap基本应用

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,resultMap 元素是 MyBatis 中最重要最强大的元素。它就是让你远离 90%的需要从结果集中取出数据的 JDBC 代码的那个东西,而且在一些情形下允许你做一些 JDBC 不支持的事情。事实
千家信息网最后更新 2026年11月04日04. Mybatis的resultMap基本应用

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

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

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

这样一个语句简单作用于所有列被自动映射到 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 一样简单。

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

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

那么如何试用外部的 resultMap:

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

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 {        // 对应的id属性    private String id;    // 对应的type属性    private Class type;    // 对应除元素外的所有属性映射关系    private List resultMappings;    // 对应所有属性映射中带有ID标志的映射关系,包括元素和的子元素    private List idResultMappings;    // 对应所有属性映射中带有Constructor标志的映射关系,包括所有子元素    private List constructorResultMappings;    // 对应所有属性映射中不带有Constructor标志的映射关系    private List propertyResultMappings;    // 对应所有属性映射中的column属性的集合    private Set mappedColumns;    // 鉴别器,对应元素    private Discriminator discriminator;    // 是否含有嵌套的结果映射,    // 如果某个属性映射存在resultMap属性,且不存在resultSet属性,则为true    private boolean hasNestedResultMaps;    // 是否含有嵌套查询,    // 如果某个属性映射存在select属性,则为true    private 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();      resultMapping.composites = new ArrayList();      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 notNullColumns) {      resultMapping.notNullColumns = notNullColumns;      return this;    }    public Builder columnPrefix(String columnPrefix) {      resultMapping.columnPrefix = columnPrefix;      return this;    }    public Builder flags(List flags) {      resultMapping.flags = flags;      return this;    }    public Builder typeHandler(TypeHandler typeHandler) {      resultMapping.typeHandler = typeHandler;      return this;    }    public Builder composites(List composites) {      resultMapping.composites = composites;      return this;    }    public Builder lazy(boolean lazy) {      resultMapping.lazy = lazy;      return this;    }    public ResultMapping build() {      // lock down collections      resultMapping.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 nestedResultMapId      if (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 typehandler      if (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 rest      if (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元素中,除了子元素以外的其他元素都会生成此类型实例, * 其中包括: *  *  * 内部包含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 notNullColumns;    // 对应元素的columnPrefix属性    private String columnPrefix;    // 处理后的标志,标志共两个:id和constructor    private List flags;    // 对应元素的column属性拆分后生成的结果,composites.size()>0会时column为null    private List composites;    // 对应元素的resultSet属性    private String resultSet;    // 对应元素的foreignColumn属性    private String foreignColumn;    // 是否延迟加载,对应元素的fetchType属性值,lazy则为true否则为false    // 也直接从配置对象中读取    private boolean lazy;}
属性 元素 结果 语句 字段 标志 类型 数据 应用 之间 代码 对象 复杂 精确 别名 名称 实例 就是 情况 数据结构 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网与科技金融数据 万易互联网科技有限公司 奇酷互联网络科技 睿民互联网科技 顺玮阁互联网科技 互联网科技素材视频竖屏 互联网汽车科技小镇 玖二柒互联网科技公司待遇 成都互联网科技公司100强 互联网科技项目计划书材料类 深圳市优智互联网科技有限公司 互联网金融科技名词解释 伊宁互联网科技做什么的 众安科技工业互联网合作 梅州GM互联网络科技有限公司 福建互联网展示科技馆设计 容联科技互联网电商 西安左小互联网科技有限公司 张家口科技产业互联网平台 科技互联网专业工作会议发言稿 广西互联网科技公司 四川狮子座互联网科技 合肥互联网科技公司公章图片 广东工业互联网大赛深圳学泰科技 美国互联网科技公司 互联网风格科技公司名称 互联网科技手机排行榜 易租星互联网科技有限公司 现代互联网科技公司 河南商务圈互联网科技有限公司
0