MyBatis中<collection>标签的多种用法

 更新时间:2025年04月02日 09:26:53   作者:愿你天黑有灯下雨有伞  
collection标签是处理一对多关系的关键工具,它能够将查询结果巧妙地映射到Java对象的集合属性中,本文主要介绍了MyBatis中<collection>标签的多种用法,感兴趣的可以了解一下

在 MyBatis 中,<collection> 标签是处理一对多(One-to-Many)关系的关键工具,它能够将查询结果巧妙地映射到 Java 对象的集合属性中。以下是 <collection> 的不同用法及其示例,结合知识库中的信息整理如下:

一、嵌套查询(Nested Select)

通过 select 属性引用另一个 SQL 查询,根据主表的某一列(如 id)作为参数,查询子表的集合数据。

特点

  • 每条主记录会触发一次子查询(可能导致 N+1 问题)。

  • 适合数据量较小或需要递归查询的场景。

示例代码

<!-- 主表的resultMap -->
<resultMap id="UserMap" type="User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <!-- 集合属性:permissions -->
    <collection 
        property="permissions" 
        ofType="Permission" 
        select="com.example.mapper.PermissionMapper.selectByUserId" 
        column="id"
    />
</resultMap>

<!-- 主表的查询SQL -->
<select id="selectUser" resultMap="UserMap">
    SELECT id, username FROM users WHERE id = #{id}
</select>

<!-- 子查询(PermissionMapper.xml) -->
<select id="selectByUserId" resultType="Permission">
    SELECT * FROM permissions WHERE user_id = #{id}
</select>

解释

  • property="permissions" :映射到 User 类的 permissions 集合属性。

  • ofType="Permission" :指定集合元素的类型。

  • select="..." :引用子查询的 Mapper 方法。

  • column="id" :将主表的 id 作为参数传递给子查询。

二、嵌套结果(Nested Results)

通过 column 和 ofType 直接映射 JOIN 查询的结果,避免多次查询数据库。

特点

  • 通过 JOIN 一次性获取所有数据,减少查询次数。

  • 需要处理重复数据(主表字段会被重复,需通过 columnPrefix 区分)。

示例代码

<!-- 主表的resultMap -->
<resultMap id="UserMap" type="User">
    <id property="id" column="user_id"/>
    <result property="username" column="username"/>
    <!-- 集合属性:orders -->
    <collection 
        property="orders" 
        ofType="Order" 
        columnPrefix="order_"
    >
        <id property="orderId" column="order_id"/>
        <result property="amount" column="amount"/>
    </collection>
</resultMap>

<!-- 主表的查询SQL(使用JOIN) -->
<select id="selectUserWithOrders" resultMap="UserMap">
    SELECT 
        u.id AS user_id, 
        u.username, 
        o.id AS order_id, 
        o.amount 
    FROM users u 
    LEFT JOIN orders o ON u.id = o.user_id 
    WHERE u.id = #{id}
</select>

解释

  • columnPrefix="order_" :将子表字段名前缀(如 order_id)与主表字段区分开。

  • <collection> 内部定义子表字段的映射规则。

  • 主表字段(如 user_id)和子表字段(如 order_id)通过别名区分。

三、递归查询(Recursive Query)

用于构建层级结构(如树形菜单、权限结构),通过 <collection> 自引用实现递归。

特点

  • 通过 select 属性引用自身或同级的查询方法,形成递归调用。

  • 适用于组织结构、分类树等场景。

示例代码

<!-- 处理树形结构的resultMap -->
<resultMap id="CategoryMap" type="Category">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <result property="parentId" column="parent_id"/>
    <!-- 递归查询子节点 -->
    <collection 
        property="children" 
        ofType="Category" 
        select="selectCategoriesByParentId" 
        column="id"
    />
</resultMap>

<!-- 查询父节点的子节点 -->
<select id="selectCategoriesByParentId" resultMap="CategoryMap">
    SELECT * FROM categories WHERE parent_id = #{id}
</select>

解释

  • column="id" :将当前节点的 id 作为父节点 ID 传递给子查询。

  • <collection> 引用同一个 Mapper 中的 selectCategoriesByParentId 方法,形成递归。

  • 直到没有子节点时停止递归。

四、使用 column 传递多个参数

当子查询需要多个参数时,可以通过表达式指定多个列。

语法

column="{param1=column1, param2=column2}"

示例代码

<collection 
    property="items" 
    ofType="Item" 
    select="com.example.mapper.ItemMapper.selectItemsByUserAndDate" 
    column="{userId=id, date=createTime}"
/>

解释

  • 子查询 selectItemsByUserAndDate 需要两个参数:userId 和 date

  • column 表达式将主表的 id 映射为 userIdcreateTime 映射为 date

五、javaType 和 ofType 的区别

  • ofType :必须指定,用于定义集合中元素的类型(如 Permission)。

  • javaType :可选,指定集合的类型(如 ArrayList)。若不指定,MyBatis 默认使用 List

示例

<!-- 显式指定javaType -->
<collection 
    property="permissions" 
    javaType="ArrayList" 
    ofType="Permission" 
    select="..." 
    column="..."
/>

总结:不同场景的适用性

场景推荐用法优缺点
简单的一对多关系嵌套查询(select)简单易用,但可能引发 N+1 问题
需要 JOIN 一次性获取数据嵌套结果(columnPrefix)减少查询次数,但需处理重复字段和复杂 SQL
树形结构(如菜单、分类)递归查询(自引用)简洁且可自动构建层级,但需注意性能(尤其数据量大时)
需要传递多个参数column 表达式灵活传递多个参数,但需确保子查询参数匹配

通过合理选择 <collection> 的用法,可以高效地处理 MyBatis 中的一对多映射需求。

到此这篇关于MyBatis中<collection>标签的多种用法的文章就介绍到这了,更多相关MyBatis  collection标签内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Springboot整合quartz实现多个定时任务实例

    Springboot整合quartz实现多个定时任务实例

    这篇文章主要介绍了Springboot整合quartz实现多个定时任务代码实例,Quartz 是一款功能强大的开源任务调度框架,几乎可以集成到任何 Java 应用程序中,Quartz 可用于创建简单或复杂的任务调度,用以执行数以万计的任务,需要的朋友可以参考下
    2023-08-08
  • Java如何利用线程池和Redis实现高效数据入库

    Java如何利用线程池和Redis实现高效数据入库

    文章介绍了如何利用线程池和Redis在高并发环境中实现高效的数据入库,通过将数据首先存储在Redis缓存中,然后利用线程池定期批量入库处理,确保系统的性能和稳定性,主要组件包括BatchDataStorageService、CacheService和RedisUtils等
    2025-02-02
  • SpringBoot中将@Bean方法解析为BeanDefinition详解

    SpringBoot中将@Bean方法解析为BeanDefinition详解

    这篇文章主要介绍了SpringBoot中将@Bean方法解析为BeanDefinition详解,得到的BeanDefinition是ConfigurationClassBeanDefinition类型,会为BeanDefinition设置factoryMethodName,这意味着当实例化这个bean的时候将采用工厂方法,需要的朋友可以参考下
    2023-12-12
  • Spring拦截器中注入Bean失败解放方案详解

    Spring拦截器中注入Bean失败解放方案详解

    这两天遇到SpringBoot拦截器中Bean无法注入问题。下面介绍关于SpringBoot拦截器中Bean无法注入的问题解决方案,感兴趣的朋友一起看看吧
    2022-06-06
  • MybatisPlus实现数据权限隔离的示例详解

    MybatisPlus实现数据权限隔离的示例详解

    Mybatis Plus对Mybatis做了无侵入的增强,非常的好用,今天就给大家介绍它的其中一个实用功能:数据权限插件,感兴趣的可以跟随小编一起了解下
    2024-04-04
  • Java命令行运行错误之找不到或无法加载主类问题的解决方法

    Java命令行运行错误之找不到或无法加载主类问题的解决方法

    这篇文章主要给大家介绍了关于Java命令行运行错误之找不到或无法加载主类问题的解决方法,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-01-01
  • Java编程简单应用

    Java编程简单应用

    本文主要介绍了三个简单Java小程序———1、HelloWorld(HelloWorld的来源);2、输出个人信息3、输出特殊图案。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • Java中继承、多态、重载和重写介绍

    Java中继承、多态、重载和重写介绍

    这篇文章主要介绍了Java中继承、多态、重载和重写介绍,需要的朋友可以参考下
    2014-07-07
  • JVM虚拟机性能监控与故障处理工具介绍

    JVM虚拟机性能监控与故障处理工具介绍

    这篇文章主要为大家介绍了JVM虚拟机性能监控与故障处理工具介绍,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • Jenkins初级使用过程中的异常处理

    Jenkins初级使用过程中的异常处理

    这篇文章主要为大家介绍了Jenkins初级使用过程中的异常处理,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04

最新评论