Mybatis之ResultMap和ResultType用法和对比


MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

前言

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

一、ResultMap是什么?

MyBatis 中的 ResultMap 是一个核心组件,属于MyBatis 返回操作结果的一个标签,用于将 SQL 中select标签查询出来的结果集映射到 Java 对象。当数据库表结构与 Java 实体类中的字段不完全匹配时(如列名与属性名不一致、存在复杂嵌套关系等),ResultMap 可以自定义映射规则,解决这种不匹配问题。

1、ResultMap特性

ResultMap 标签包括两个重要属性:

  • id 属性:唯一标识, 用于表示这个ResultMap 的唯一性。在使用 select 标签 ResultMap 属性时,就是通过它引用的。
  • type 属性:表示该 ResultMap 的结果集映射类型,可以为类的全限定名或者别名。这时候我们就可以定义一个 ResultMap ,来映射结果集中不一样的字段。

1.1 常用子元素

子元素作用
<id>指定主键映射,提高 MyBatis 性能优化能力。
<result>普通字段映射,用于简单类型(如 String, Integer)。包括两个属性,column:数据库表的列名,是数据库字段名或者用as定义的别名。property:实体类的属性,和列名一模一样,以进行一一映射。
<association>一对一或多对一关系,映射到嵌套对象(如 User 中的 Address)。(见3.2)
<collection>一对多关系,映射到集合(如 User 中的 List)。(见3.3)
<discriminator>用于实现结果集的条件映射,即多态映射,根据列值选择不同的子类型(高级用法)。

<discriminator>的用法比较灵活,详细介绍可以移步Mybatis之ResultMap中的discriminator标签介绍

1.2 高级特性

  • 延迟加载(Lazy Loading)
    通过配置 fetchType=“lazy”,可以实现嵌套对象的延迟加载:
<association property="user" column="user_id" javaType="User" 
             resultMap="userResultMap" fetchType="lazy" />
  • 自动映射(Auto Mapping)
    当列名与属性名存在简单对应关系(如 user_name → userName)时,可使用 autoMapping=“true” 简化配置:
<resultMap id="userResultMap" type="User" autoMapping="true">
    <!-- 仅需配置不一致的字段 -->
    <id property="userId" column="user_id" />
</resultMap>
  • 使用 片段复用映射逻辑
<sql id="userColumns">
    user_id, user_name, create_time
</sql>

<select id="getUserById" resultMap="userResultMap">
    SELECT <include refid="userColumns" /> FROM users WHERE user_id = #{id}
</select>

2、 ResultMap的核心作用

2.1、处理列名与属性名不一致

例如,数据库字段采用snake_case(例:user_name),而 Java 属性使用camelCase(例:userName)。

2.2、处理复杂嵌套关系

例如,将多表联查的结果映射到嵌套对象或集合(如 一个用户对应多个订单这种情况,User 对象包含 List)。

2.3、自定义类型转换

当需要把数据库中的类型转换为 Java 中的特定类型时。

2.4、优化查询性能

通过 association 和 collection 实现延迟加载(Lazy Loading)。

3、 ResultMap的基本用法

3.1、 简单映射(处理列名与属性名不一致)

创建数据库表:

CREATE TABLE users (
  user_id INT PRIMARY KEY,
  user_name VARCHAR(50),
  create_time DATETIME
);

Java对象:

public class User {
    private Integer userId;     // 对应 user_id 列
    private String userName;    // 对应 user_name 列
    private LocalDateTime createTime; // 对应 create_time 列
    // getters/setters
}

resultMap配置:

<resultMap id="userResultMap" type="User">
    <id property="userId" column="user_id" />        <!-- 主键映射 -->
    <result property="userName" column="user_name" /> <!-- 普通字段映射 -->
    <result property="createTime" column="create_time" />
</resultMap>

SQL映射:

<select id="getUserById" resultMap="userResultMap">
    SELECT user_id, user_name, create_time 
    FROM users 
    WHERE user_id = #{id}
</select>

这里会根据resultMap的配置将SQL的查询结果user_id, user_name, create_time,一一映射到Java实体类的属性userId,userName,createTime。

注意:如果数据库字段和实体类属性一致的情况下,可以省略不写。

3.2、复杂映射(处理复杂嵌套关系)

例:1:数据库表:

CREATE TABLE orders (
  order_id INT PRIMARY KEY,
  user_id INT,
  order_number VARCHAR(50),
  FOREIGN KEY (user_id) REFERENCES users(user_id)
);

Java对象:

public class Order {
    private Integer orderId;
    private String orderNumber;
    private User user; // 关联的用户对象
    // getters/setters
}

resultMap配置:

<resultMap id="orderResultMap" type="Order">
    <id property="orderId" column="order_id" />
    <result property="orderNumber" column="order_number" />
    
    <!-- 嵌套对象映射:使用 association -->
    <association property="user" column="user_id" javaType="User" resultMap="userResultMap" />
</resultMap>

SQL映射:

<select id="getOrderWithUser" parameterType="int" resultMap="orderResultMap">
	-- resultMap="orderResultMap":使用之前定义的 resultMap 处理嵌套映射
  SELECT 
    o.order_id,
    o.order_number,
    o.user_id,
    u.user_id AS "user.user_id",  -- 使用AS "user.user_id"别名映射到嵌套对象,需确保别名中的user与resultMap中property="user"一致
    u.user_name AS "user.user_name",  -- 嵌套User对象的属性
    u.create_time AS "user.create_time"  -- 嵌套User对象的属性
    -- 确保userResultMap中定义的column与查询中的别名一致
  FROM orders o
  LEFT JOIN users u ON o.user_id = u.user_id
  WHERE o.order_id = #{orderId}
</select>

注意:对于复杂嵌套,可以考虑使用columnPrefix简化映射配置

例2:假设用户表和地址表存在一对一的关系,用户表有id、user_name、address_id字段,地址表有id、street、city等字段。可以通过以下方式配置嵌套映射:

<resultMap id="userWithAddressResultMap" type="User">
  <id property="id" column="id" />
  <result property="userName" column="user_name" />
  <association property="address" javaType="Address">
    <id property="id" column="address_id" />
    <result property="street" column="street" />
    <result property="city" column="city" />
  </association>
</resultMap>
<select id="getUserWithAddress" parameterType="int" resultMap="userWithAddressResultMap">
  SELECT u.id, u.user_name, a.id as address_id, a.street, a.city
  FROM users u
  LEFT JOIN addresses a ON u.address_id = a.id
  WHERE u.id = #{id}
</select>

3.3、集合映射(一对多关系)

Java对象:

public class User {
    private Integer userId;
    private String userName;
    private List<Order> orders; // 用户的订单列表
    // getters/setters
}

resultMap配置:

<resultMap id="userWithOrdersResultMap" type="User">
    <id property="userId" column="user_id" />
    <result property="userName" column="user_name" />
    
    <!-- 集合映射:使用 collection -->
    <collection property="orders" ofType="Order" resultMap="orderResultMap" />
</resultMap>

查询需要获取用户及其关联的所有订单数据对应的SQL查询映射:

<select id="getUserWithOrders" parameterType="int" resultMap="userWithOrdersResultMap">
  SELECT 
    u.user_id,
    u.user_name,
    o.order_id AS "orders.order_id",
    o.order_number AS "orders.order_number",
    o.user_id AS "orders.user_id"  -- 用于嵌套Order中的user对象关联(通过orderResultMap)
  FROM users u
  LEFT JOIN orders o ON u.user_id = o.user_id
  WHERE u.user_id = #{userId}
</select>

注意:MyBatis 会自动将相同user_id的记录合并,并将不同的order_id记录映射到orders列表中。

例2,假设一个用户可以有多个订单,订单表有id、order_number、user_id等字段。可以通过以下方式配置集合映射:

<resultMap id="userWithOrdersResultMap" type="User">
  <id property="id" column="id" />
  <result property="userName" column="user_name" />
  <collection property="orders" ofType="Order">
    <id property="id" column="order_id" />
    <result property="orderNumber" column="order_number" />
  </collection>
</resultMap>

对应的SQL查询语句,

<select id="getUserWithOrders" parameterType="int" resultMap="userWithOrdersResultMap">
  SELECT u.id, u.user_name, o.id as order_id, o.order_number
  FROM users u
  LEFT JOIN orders o ON u.id = o.user_id
  WHERE u.id = #{id}
</select>

二、ResultType是什么?

MyBatis 的resultType,顾名思义,返回结果,是一种简化的结果映射方式,用于将 SQL 查询结果直接映射到 Java 对象,可以理解为期望从这条语句中返回结果的类全限定名或别名(如:java.lang.String对应的别名是“string”)。与resultMap相比,它不需要显式定义字段与属性的映射关系,适用于简单场景。下面从基本概念、使用场景、与resultMap的对比等方面进行详细介绍。

1.基本概念

resultType是 MyBatis 中用于指定查询结果类型的属性,它可以是 Java 基本类型、POJO 类、Map 等。MyBatis 会根据查询结果列名与 Java 对象属性名的匹配关系(默认不区分大小写)自动进行映射。

2.ResultType的核心作用

  • 简单查询:当查询结果与 Java 对象属性名完全一致或符合驼峰命名规则时。
  • 动态结果:返回 Map 或 List类型,适用于不确定具体字段的场景。
  • 聚合函数:返回单个值(如 COUNT、SUM 等)。

3.简单示例

3.1 返回 POJO 对象

假设存在用户表,表中有id、user_name、email等字段,对应的 Java 类为User,包含id、userName、email属性。可以使用以下配置:

<select id="getUserById" parameterType="int" resultType="User">
  SELECT id, user_name, email
  FROM users
  WHERE id = #{id}
</select>

MyBatis 会自动将user_name映射到userName(基于驼峰命名规则)。

3.2 返回基本类型

<select id="getUserCount" resultType="int">
  SELECT COUNT(*) FROM users
</select>

3.3 返回 Map

<select id="getUserAsMap" parameterType="int" resultType="map">
  SELECT id, user_name, email
  FROM users
  WHERE id = #{id}
</select>

返回结果为:

{id=1, user_name=John, email=john@example.com}

3.4 返回 List

<select id="getAllUsers" resultType="map">
  SELECT id, user_name, email
  FROM users
</select>

返回结果为:

[
  {id=1, user_name=John, email=john@example.com},
  {id=2, user_name=Jane, email=jane@example.com}
]

注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。即,这里返回的是Map的集合List<Map>,resultType属性设置的为集合包含的类型即Map。

三、ResultMap与 ResultType 的对比

特性ResultMapResultType
映射方式自定义映射规则自动映射(基于列名与属性名的匹配)
适用场景复杂查询,存在列名与属性名不一致或嵌套关系简单查询,列名与属性名完全一致
灵活性高(完全自定义)低(依赖命名规则)

四、总结

ResultType是 MyBatis 提供的一种简化结果映射方式,适用于简单场景,可以减少配置工作量。而 ResultMap则适用于复杂的映射需求,提供了更强大的功能。ResultType不需要配置,但是ResultMap要配置。ResultType是直接指定返回类型的,而使用ResultMap时,需要在外部ResultMap标签中,设置数据库表的字段名和实体bean对象类属性的一一对应关系。设置后,就算数据库的字段名和实体类的属性名不一样也没有关系,Mybatis依然会给映射出来,所以ResultMap要更强大一些。在实际开发中,应根据具体场景选择合适的映射方式。需要注意的是,在select元素中ResultType和 ResultMap之间只能同时使用一个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值