MyBatis标签之resultType和resultMap

摘要:Mybatis 中 select 标签有两个属性 resultType 和 resultMap,主要作用是在mapper.xml文件中,配置实体类中的字段与数据库表中的字段关联映射。本文介绍它们的使用方法和区别。

1 MyBatis动态SQL之if 语句
2 MyBatis动态sql之where标签|转
3 MyBatis动态SQL之set标签|转
4 MyBatis动态SQL之trim元素|转
5 MyBatis动态sql中foreach标签的使用
6 MyBatis动态SQL之choose(when、otherwise)语句
7 MyBatis动态SQL之bind标签|转
8 MyBatis标签之 resultType和resultMap

MyBatis常用动态标签大全见上述URL,它们大概分为如下四类:

标签 作用 使用场景
foreach 循环语句 批量添加或者批量查询
if 条件判断语句 单条件分支判断
choose、when、otherwise 类似 Java 中的 switch、case、default 语句 多条件分支判断
trim、where、set 辅助标签 用于处理一些条件查询

  在MyBatis中有一个ResultMap标签,它是为了映射select标签查询出来的结果集,其主要作用是将实体类中的字段与数据库表中的字段进行关联映射。

前言

  在Mybatis select 标签中有两个工作中经常使用的属性 resultTyperesultMap,用于在mapper.xml文件中配置结果集的数据类型。在日常开发中,应该如何正确的选择 resultTyperesultMap?下面我们对这两个标签分别进行讲解和演示。

结果类型resultType

  resultType直译就是结果的类型,可以设置为期望从select 语句中返回结果集的全限定名别名。resultType使用场景如下:

  如果查询结果是一个简单的数据类型,比如基本数据类型String、map、int或者一个简简单单的JavaBean,那么,可以使用resultType指定输出结果集的数据类型。

  测试用例需要完成的功能如下:在查询用户表时,需要将user_id、user_name 和 hashed_password 的值映射到 User 对象的 userId 、 userName 和 hashedPassword 属性上。我们先学习一个使用resultType返回一个map对象的简单映射语句示例:

<sql id="resultTypeColumn">
    user_id             as "id",
    user_name           as "userName",
    hashed_password     as "hashedPassword"
</sql>
<select id="selectUser" resultType="map">
  select 
  	<include refid="resultTypeColumn"/>
  from t_user
  where id = #{id}
</select>

  指定 resultType 返回值类型为 HashMap 类型时,HashMap 对应的别名是 “map”。上述查询语句只是简单地将所有的列映射到 HashMap 的键上,这由 resultType 属性指定。此select豫剧在查询字段时用了一个 sql 标签<sql id="resultTypeColumn">进行封装,该 sql 片段可被复用。

  返回一个字符串:

<select id="getUserNameById" resultType="string">
	SELECT user_name as userName FROM t_user WHERE id = #{id}
</select>

  指定 resultType 返回值类型为 String 类型时,java.lang.String对应的别名是“string”。

  还有一种情况就是返回一个实体类对象,要求数据库表的字段名和实体bean对象的属性名一样。虽然在大部分情况下都够用,但是 HashMap 并不是一个很好的领域模型;你的程序更可能会使用 JavaBean 或 POJO(普通老式 Java 对象)作为领域模型,MyBatis 对两者都提供了支持。看看下面这个 JavaBean:

package com.someapp.model;
public class User {
  private int id;
  private String userName;
  private String hashedPassword;

 // omit getter,setter and toString
}

  基于 JavaBean 的规范,上面这个类有 3 个属性:id,userName 和 hashedPassword,它们各自对应到 select 语句中的列名。这样的一个 JavaBean 可以被映射到 ResultSet,就像映射到 HashMap 一样简单。

<select id="selectUser" resultType="com.someapp.model.User">
  select 
  <include refid="resultTypeColumn"/>
  from t_user
  where id = #{id}
</select>

返回一个List:

<select id="selectUsers" resultType="com.someapp.model.User">
  select 
  <include refid="resultTypeColumn"/>
  from t_user
  where user_name like '%胡杨%'
</select>

  类型别名是你的好帮手,关于如何设置类型别名,请移步《Spring Boot MyBatis使用type-aliases-package自定义类别名》。使用别名后就可以不用输入类的全限定名了。譬如:

<select id="selectUsers" resultType="User">
  select 
  <include refid="resultTypeColumn"/>
  from t_user
  where id = #{id}
</select>

  在此情况下,MyBatis 会在幕后自动创建一个 resultMap,再根据属性名把列映射到 JavaBean 的同名属性上。如果列名和属性名不完全相等,可以在 SELECT 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配。例如:

<sql id="resultTypeColumn">
    user_id             as "id",
    user_name           as "userName",
    hashed_password     as "hashedPassword"
</sql>
<select id="selectUsers" resultType="map">
  select 
  	<include refid="resultTypeColumn"/>
  from t_user
  where id = #{id}
</select>

  注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。

结果映射resultMap

  resultMap 直译就是结果映射,它是 MyBatis 中最复杂最彪悍的元素,用来描述如何从数据库结果集中加载对象。与 resultType 相比,resultMap标签强大许多,它不仅能够用于简单查询,还能用于级联查询以及设置缓存,功能可谓是十分的丰富。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并允许我们在一些场景下执行一些 JDBC 不支持的操作。实际上,在为一些比如多表连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂的语句只需要描述语句之间的关系就行了。温馨提示,resultType 和 resultMap 不能同时存在,只能使用其中一个。

resultMap标签属性

  如果数据库中表的字段与User类的属性名称不一致,我们就可以使用resultMap来返回。resultMap 标签包括两个重要属性:

    id 属性:唯一标识, 用于表示这个resultMap的唯一性。在使用 select 标签 resultMap 属性时,就是通过它引用的。

    type 属性:表示该 resultMap 的结果集映射类型,可以为类的全限定名或者别名。这时候我们就可以定义一个resultMap,来映射结果集中不一样的字段。

  resultMap子标签的全部属性如下:

子标签 功能 备注
id 指定查询列中的唯一标识,如果有多个列组成唯一标识,配置多个id 可以不用
result 用于标识一些简单属性,包括column和property两个属性 常用
association 在主表的pojo中嵌套另一个表的pojo 不推荐使用
collection 把查询到的多条记录映射到集合对象 不推荐使用

  其中,result标签的属性包括两个:

  1. column:数据库表的列名,是数据库字段名或者用as定义的别名。
  2. property:实体类的属性,和列名一模一样,以进行一一映射。

resultMap使用示例

  下面使用一个简单的例子,来介绍 resultMap 的使用方法。虽然上一节中的例子不用显式配置 resultMap,但为了讲解,我们来看看如果显式使用外部的 resultMap 会怎样;这也是解决列名和bean名不匹配的另外一种方式。定义一个resultMap:

<resultMap id="userResultMap"(唯一标识) type="User"(映射的数据类型,支持别名)>
  <!-- column是数据库中表的字段名,property是实体类的属性名 -->
  <id property="id"(用于映射主键字段) column="user_id" />
  <result property="userName" column="userName"/>
  <result(用于映射一般字段) property="password" column="hashed_password"/>
</resultMap>

  然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)。比如:

<select id="selectUser" resultMap="userResultMap">
  select user_id, user_name as userName, hashed_password
  from t_user
  where id = #{id}
</select>

查询结果集的数据类型是List<User>

<select id="selectAllusers" resultMap="userResultMap">
	select * from t_user;
</select>

其中,user_name as userName 的功能是为字段 user_name 设置别名userName,因此,resultMap标签中column就必须写作userName,保持列名一致。

  如果一个JavaBean中某些属性为来自另一张表的list,则可以使用collection标签,本文不做介绍。

resultType和resultMap的区别

  下面了解一下MyBatis中结果集数据类型转换机制:在MyBatis进行查询映射时,查询出来的每一个属性都是放在一个对应的Map里面的,其中键是属性名,值是键对应的值。当提供的结果集类型属性是resultType时,MyBatis会将Map里面的键值对取出赋给resultType所指定对象对应的属性。所以,MyBatis的每一个查询映射的结果集数据类型其实都是ResultMap,只是当提供的返回类型是resultType时,MyBatis会自动映射,把键值对赋给resultType所指定对象的属性。而当提供的返回类型是resultMap的时候,因为Map不能很好表达领域模型,我们就需要自己把它转化为对应的对象,这常常在复杂查询中很有作用。

  言归正传,resultType和resultMap到底有什么区别呢?

  resultType不需要配置,但是resultMap要配置。resultType是直接指定返回类型的,而使用resultMap时,需要在外部ResultMap标签中,设置数据库表的字段名和实体bean对象类属性的一一对应关系。设置后,就算数据库的字段名和实体类的属性名不一样也没有关系,mybatis依然会给映射出来,所以resultMap要更强大一些。

  就像上面说的那样,如果查询出来数据库字段名(包括字段别名)和要封装的实体bean对象属性值不相同时,只能使用resultMap来返回结果。

  还有一个区别是resultMap可以用在复杂联合查询上,而resultType不可以。关于这一点,大家可以去Mybatis官网了解一下,这里点到为止。

结束语

  至此,大家已经了解了resultType和resultMap的基本用法,在日常业务开发中已经可以游刃有余了。如果想更上一层楼,掌握更多关于resultMap的高级用法,请移步Mybatis官网

  你遇到这个话题的时候,通常怎么理解呢?你碰到过特别精彩、让人印象深刻的回答吗?欢迎大家积极留言交流。

  更新于2024年2月4日。

Reference

posted @ 2022-09-18 19:52  楼兰胡杨  阅读(3496)  评论(0编辑  收藏  举报