You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MyBatis如何用@Results实现一对多映射(不使用@One/@Many)

不用@One/@Many,单SQL+@Results实现一对多映射

核心思路

通过**SQL关联查询(左连接/内连接)**一次性查出主表+子表的所有数据,再通过@Results配置主实体的唯一标识(id=true),让MyBatis自动将同主实体的多条子记录合并为集合,无需嵌套查询(也就不会生成多条SQL)。

具体实现步骤

1. 定义实体类

以用户(User)和用户订单(UserOrder)为例,User包含一对多关联的订单集合:

public class User {
    private Long id;
    private String username;
    // 一对多关联的订单集合
    private List<UserOrder> orders;
    // getter/setter 省略
}

public class UserOrder {
    private Long id;
    private String orderNo;
    private Long userId;
    // getter/setter 省略
}

2. 编写关联查询SQL与@Results映射

在Mapper接口中定义查询方法,用左连接一次性拉取用户和对应所有订单,直接在同一个@Results里完成主、子实体的映射,无需额外子查询方法:

@Select("SELECT u.id as user_id, u.username, o.id as order_id, o.order_no, o.user_id " +
        "FROM user u LEFT JOIN user_order o ON u.id = o.user_id " +
        "WHERE u.id = #{userId}")
@Results(id = "UserWithOrdersResultMap", value = {
        // 标记主实体User的唯一id,MyBatis靠这个识别同一条主记录,合并子数据
        @Result(column = "user_id", property = "id", id = true),
        @Result(column = "username", property = "username"),
        // 直接映射集合内子实体的属性,无需指定select方法
        @Result(column = "order_id", property = "orders.id"),
        @Result(column = "order_no", property = "orders.orderNo"),
        @Result(column = "user_id", property = "orders.userId")
})
User getUserWithOrders(@Param("userId") Long userId);

3. 关键注意点

  • 必须标记主实体的唯一id:@Result(..., id = true)是MyBatis合并同主实体多条子记录的核心,没有这个配置会生成多个重复的主实体对象。
  • 避免列名冲突:SQL中给重复的列(如主表id和子表id)起别名(如user_id、order_id),防止映射时混淆。
  • 无需额外子查询方法:你之前写的selectUserProfile()属于冗余代码,单SQL查询下直接在同一@Results内映射子实体属性即可。

常见问题排查

如果出现集合为空或主实体重复的情况:

  • 检查主实体的id=true标记是否正确配置。
  • 核对SQL的关联条件是否正确,确保子表外键与主表主键关联无误。
  • 确认@Result的column属性与SQL中的列名(含别名)完全匹配。

内容的提问来源于stack exchange,提问作者1515biubiubiu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 16:42:35