MyBatis里ResultMap那个Association和Collection标签到底怎么用,细节和区别都说清楚点
- 问答
- 2026-01-18 07:55:28
- 3
一对一用 association,一对多用 collection。
你的 Java 类之间有关联关系,比如一个订单(Order)属于一个用户(User),这是“一对一”(一个订单只对应一个用户),而一个用户(User)有多个订单(Order),这就是“一对多”,数据库里用外键表示这种关系,但查出来放到 Java 对象里,就需要 association 和 collection 来帮忙。
association 标签:处理“有一个”的关系(一对一)
当你的主对象(Order)里面包含了一个单独的附属对象(User),就用 association。
举个例子:订单和用户
-
数据库表:
orders表有一个user_id字段指向user表的主键。 -
Java 类:

public class Order { private Integer id; private String orderNumber; // 这个订单属于哪个用户?是一个完整的 User 对象 private User user; // 这就是“一对一”关系 // ... getter and setter } public class User { private Integer id; private String username; // ... getter and setter }
目标:查询订单时,希望能直接把对应的用户信息也查出来,并填充到 Order 对象的 user 属性里。
怎么用 association?有两种主要方式:
嵌套结果映射(推荐,一次查询)
这种方式是写一个复杂的 SQL 联表查询,然后用 association 告诉 MyBatis 结果集的哪部分映射到 user 对象。
<select id="findOrderWithUser" resultMap="OrderUserResultMap">
SELECT
o.id as order_id,
o.order_number,
u.id as user_id,
u.username
FROM orders o
LEFT JOIN user u ON o.user_id = u.id
WHERE o.id = #{id}
</select>
<resultMap id="OrderUserResultMap" type="Order">
<!-- 先映射 Order 本身的属性 -->
<id property="id" column="order_id"/>
<result property="orderNumber" column="order_number"/>
<!-- 关键在这里:使用 association 映射关联的 User 对象 -->
<association property="user" javaType="User">
<!-- 在 association 标签内部,映射 User 对象的属性 -->
<!-- 注意这里的 column 是上面 SELECT 语句里起的别名 -->
<id property="id" column="user_id"/>
<result property="username" column="username"/>
</association>
</resultMap>
property="user":对应 Order 类里的user属性名。javaType="User":告诉 MyBatis 这个属性对应的 Java 类型是什么。- 优点:只需要一次数据库查询,效率高。
嵌套查询(需要多次查询) 这种方式是先查主对象(Order),然后根据查到的外键(user_id)再去执行另一个查询(getUser)来获取关联对象(User)。
<select id="findOrderWithUser" resultMap="OrderUserResultMap">
SELECT * FROM orders WHERE id = #{id}
</select>
<select id="getUser" resultType="User">
SELECT * FROM user WHERE id = #{userId}
</select>
<resultMap id="OrderUserResultMap" type="Order">
<id property="id" column="id"/>
<result property="orderNumber" column="order_number"/>
<!-- 关键在这里:通过 select 属性指定另一个查询的 id -->
<!-- 通过 column 属性将当前结果中的 user_id 值传递给 getUser 查询 -->
<association property="user" column="user_id" javaType="User" select="getUser"/>
</resultMap>
select="getUser":指定用来查询 User 的 SQL 映射语句的 id。column="user_id":将本查询结果中的user_id列的值作为参数传递给getUser查询。- 缺点:可能会引发“N+1 查询问题”(如果查 10 个订单,就要执行 1 次查订单 + 10 次查用户,共11次查询),效率低,但可以通过 MyBatis 的懒加载等机制缓解。
collection 标签:处理“有多个”的关系(一对多)
当你的主对象(User)里面包含了一个集合(比如订单的 List),就用 collection。

接着上面的例子:用户和订单
-
Java 类:
public class User { private Integer id; private String username; // 这个用户有哪些订单?是一个 Order 对象的集合 private List<Order> orders; // 这就是“一对多”关系 // ... getter and setter } public class Order { private Integer id; private String orderNumber; // ... getter and setter }
目标:查询用户时,希望能直接查出他所有的订单,并填充到 User 对象的 orders 属性(一个列表)里。
怎么用 collection?同样有两种方式:
嵌套结果映射(推荐,一次查询) 写一个联表查询,查出用户和他的所有订单数据。

<select id="findUserWithOrders" resultMap="UserOrdersResultMap">
SELECT
u.id as user_id,
u.username,
o.id as order_id,
o.order_number
FROM user u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.id = #{id}
</select>
<resultMap id="UserOrdersResultMap" type="User">
<!-- 先映射 User 本身的属性 -->
<id property="id" column="user_id"/>
<result property="username" column="username"/>
<!-- 关键在这里:使用 collection 映射关联的 Order 对象集合 -->
<collection property="orders" ofType="Order">
<!-- 在 collection 标签内部,映射集合中每个 Order 对象的属性 -->
<id property="id" column="order_id"/>
<result property="orderNumber" column="order_number"/>
</collection>
</resultMap>
property="orders":对应 User 类里的orders属性名。ofType="Order":这是和 association 最大的区别之一,ofType指定的是集合中的元素的 Java 类型(因为 orders 是List<Order>,所以元素类型是Order)。
嵌套查询(需要多次查询) 先查询用户,再根据用户 id 去查询订单列表。
<select id="findUserWithOrders" resultMap="UserOrdersResultMap">
SELECT * FROM user WHERE id = #{id}
</select>
<select id="getOrdersByUserId" resultType="Order">
SELECT * FROM orders WHERE user_id = #{userId}
</select>
<resultMap id="UserOrdersResultMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<!-- 关键在这里 -->
<collection property="orders" column="id" ofType="Order" select="getOrdersByUserId"/>
</resultMap>
- 逻辑和
association的嵌套查询完全一样,只是标签换成了collection,并且用ofType指定集合元素类型。
核心区别与细节总结
-
根本区别:
association:用于映射单个对象属性(一对一,多对一)。Order里面有个User。collection:用于映射集合对象属性(一对多)。User里面有个List<Order>。
-
标签属性:
association用javaType指定关联对象的类型。collection用ofType指定集合中元素的类型,这是最容易记混的点。
-
性能选择:
- 嵌套结果映射(写联表SQL):绝大多数场景推荐这个,一次SQL查询搞定,效率高。
- 嵌套查询(分两次查):只有在关联数据很大、不常用(可以用懒加载)、或者SQL过于复杂时才考虑,要警惕N+1查询问题。
-
列名冲突:在写联表查询的 SQL 时,两个表可能有同名的列(比如都有
id)。务必使用别名(AS) 来区分,并在resultMap的column属性中使用别名,这是新手常踩的坑。
你只要搞清楚你的 Java 对象是“有一个”还是“有多个”其他对象,就能决定用 association 还是 collection 了,然后优先选择写联表 SQL 配合嵌套结果映射的方式,这样最直观也最高效。
本文由寇乐童于2026-01-18发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/82915.html
