MyBatis里如何实现一对多关联查询

总结

在MyBatis中实现一对多关联查询可通过两种方式:1)在XML映射文件中使用`<collection>`标签,通过嵌套结果集(联表查询)或嵌套查询(分次查询)关联子表数据;2)使用注解方式通过`@Results`和`@Result`注解,结合`@Many`指定子查询方法。需在实体类中定义包含多个子对象的集合属性,并通过column参数传递关联字段。

详细解析

在 MyBatis 中实现一对多关联查询,主要通过 嵌套查询(分步查询) 和 嵌套结果(联表查询) 两种方式实现。以下是具体实现方法和示例:


一、嵌套查询(分步查询)
原理:先查询主实体,再根据主实体的关联字段查询子实体集合。
适用场景:子数据量较小或需要延迟加载的场景。

实现步骤:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<!-- 主查询 -->

<select id="selectUserWithOrders" resultMap="userResultMap">

    SELECT * FROM user WHERE id = #{id}

</select>

<!-- 子查询 -->

<select id="selectOrdersByUserId" resultType="Order">

    SELECT * FROM order WHERE user_id = #{userId}

</select>

<!-- 结果映射 -->

<resultMap id="userResultMap" type="User">

    <id column="id" property="id"/>

    <result column="name" property="name"/>

    <!-- 嵌套查询配置 -->

    <collection property="orders" ofType="Order" 

                select="selectOrdersByUserId" 

                column="id"/>  <!-- 传递主实体ID到子查询 -->

</resultMap>

  1. 定义实体类
    主实体类中需包含子实体的集合属性:

    1

    2

    3

    4

    5

    6

    public class User {

        private Long id;

        private String name;

        private List orders;  // 子实体集合

        // getters/setters

    }

  2. 编写 Mapper XML
    • 主查询:查询主实体并触发子查询。

    • 子查询:根据主实体 ID 查询子实体列表。

  3. 调用查询方法

    1

    2

    User user = sqlSession.selectOne("selectUserWithOrders"1);

    List orders = user.getOrders();  // 自动触发子查询

优点:逻辑清晰,适合分步加载。
缺点:可能产生 N+1 查询问题(主查询 1 次 + 子查询 N 次)。


二、嵌套结果(联表查询)
原理:通过单次 SQL JOIN 查询获取所有数据,直接映射到主实体和子实体集合。
适用场景:需要一次性加载关联数据,避免多次查询。

实现步骤:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<select id="selectUserWithOrdersJoin" resultMap="userJoinResultMap">

    SELECT 

        u.id as user_id, u.name as user_name,

        o.id as order_id, o.order_no as order_no

    FROM user u

    LEFT JOIN order o ON u.id = o.user_id

    WHERE u.id = #{id}

</select>

<resultMap id="userJoinResultMap" type="User">

    <id column="user_id" property="id"/>

    <result column="user_name" property="name"/>

    <!-- 嵌套结果映射 -->

    <collection property="orders" ofType="Order">

        <id column="order_id" property="id"/>

        <result column="order_no" property="orderNo"/>

    </collection>

</resultMap>

  1. 定义实体类
    与嵌套查询相同,主实体需包含子实体集合。

  2. 编写 Mapper XML
    • 单次 JOIN 查询:关联主表和子表。

    • 结果映射:通过collection标签映射子实体集合。

  3. 调用查询方法

    1

    2

    User user = sqlSession.selectOne("selectUserWithOrdersJoin"1);

    List orders = user.getOrders();  // 直接获取关联数据

优点:减少数据库查询次数,性能更高。
缺点:SQL 复杂度较高,需手动处理字段别名。


三、注解方式实现(MyBatis 注解驱动)
原理:通过@Results和@Many注解配置关联关系。

示例代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public interface UserMapper {

    @Select("SELECT * FROM user WHERE id = #{id}")

    @Results({

        @Result(property = "id", column = "id"),

        @Result(property = "name", column = "name"),

        // 配置一对多关联

        @Result(property = "orders",

                column = "id",

                many = @Many(select = "selectOrdersByUserId"))

    })

    User selectUserWithOrders(@Param("id") Long id);

    @Select("SELECT * FROM order WHERE user_id = #{userId}")

    List selectOrdersByUserId(@Param("userId") Long userId);

}

优点:代码简洁,适合注解驱动开发。
缺点:复杂关联时配置较繁琐。


四、对比总结

方式嵌套查询嵌套结果注解方式
查询次数多次(1+N)单次同嵌套查询
性能较低(依赖子查询)较高中等
适用场景子数据量小、延迟加载需一次性加载关联数据简单关联逻辑
配置复杂度中等较高(需处理字段映射)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值