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映射为- userId,- createTime映射为- 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标签内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- mybatis collection关联查询多个参数方式
- MyBatis使用嵌套查询collection和association的实现
- mybatis resultMap之collection聚集两种实现方式
- mybatis中association和collection的使用与区别
- MyBatis的collection和association的使用解读
- Mybatis中一对多(collection)和一对一(association)的组合查询使用
- Mybatis使用Collection属性的示例代码
- Mybatis的collection三层嵌套查询方式(验证通过)
- mybatis collection和association的区别解析
