sql语法- MyBatis 中 <collection> 标签的作用 1对多的情况

MyBatis 中 标签的这段配置

sql 复制代码
<collection property="orders" 
            ofType="com.example.Order" 
            javaType="java.util.ArrayList">
    ...
</collection>

这是 MyBatis 用于处理 一对多(1:N)关联关系 的核心配置。下面逐项解析其含义,并结合例子说明。

作用

用于将数据库查询结果中的多行数据映射为 Java 对象中的一个集合属性(如 List、Set 等)。

在你这个例子中:

主对象(比如 User)有一个属性叫 orders,类型是 List。

MyBatis 会把与该主对象关联的多个 Order 记录自动收集起来,放入 orders 集合中。

property="orders"

表示主 Java 对象(如 User 类)中有一个名为 orders 的字段。

通常是 List、Set 等集合类型。

java 复制代码
public class User {
    private Long id;
    private String name;
    private List<Order> orders; // ← 这个字段
}

ofType="com.example.Order"

指定集合中每个元素的 Java 类型。

即:orders 这个列表里装的是 Order 对象。

MyBatis 会用这个类去创建每一个子对象,并映射字段。

ofType 是 最重要的属性之一,不能省略(除非使用注解或自动推断,但 XML 中强烈建议显式声明)

javaType="java.util.ArrayList"

指定集合本身的 Java 类型。

即:orders 这个字段具体是用 ArrayList 实现的(而不是 LinkedList 或 HashSet)。

注意:javaType 在大多数情况下可以省略,因为 MyBatis 默认会使用 ArrayList 作为 List 类型的实现。只有当你需要特定集合类型(如 HashSet)时才需显式指定。

demo

java 复制代码
// 主对象
public class User {
    private Long id;
    private String name;
    private List<Order> orders; // 一对多:一个用户有多个订单

    // getters / setters
}

// 子对象
public class Order {
    private Long orderId;
    private String productName;
    private BigDecimal amount;

    // getters / setters
}
java 复制代码
-- 用户表
CREATE TABLE user (
    id BIGINT,
    name VARCHAR(100)
);

-- 订单表
CREATE TABLE order (
    order_id BIGINT,
    user_id BIGINT,
    product_name VARCHAR(100),
    amount DECIMAL(10,2)
);
sql 复制代码
<resultMap id="UserWithOrdersResult" type="com.example.User">
    <id column="id" property="id"/>
    <result column="name" property="name"/>

    <!-- 一对多映射 -->
    <collection property="orders"
                ofType="com.example.Order"
                javaType="java.util.ArrayList">
        <id column="order_id" property="orderId"/>
        <result column="product_name" property="productName"/>
        <result column="amount" property="amount"/>
    </collection>
</resultMap>
sql 复制代码
<select id="selectUserWithOrders" resultMap="UserWithOrdersResult">
    SELECT 
        u.id,
        u.name,
        o.order_id,
        o.product_name,
        o.amount
    FROM user u
    LEFT JOIN order o ON u.id = o.user_id
    WHERE u.id = #{userId}
</select>
java 复制代码
User user = new User();
user.setId(1L);
user.setName("Alice");

List<Order> orders = new ArrayList<>();
Order o1 = new Order(); o1.setOrderId(101L); o1.setProductName("iPhone"); ...
Order o2 = new Order(); o2.setOrderId(102L); o2.setProductName("iPad"); ...

orders.add(o1);
orders.add(o2);
user.setOrders(orders); // 自动注入!

如果不用 JOIN,而是分两次查(嵌套查询)呢?

java 复制代码
<collection property="orders"
            ofType="com.example.Order"
            select="selectOrdersByUserId"
            column="id" />

此时 MyBatis 会先查用户,再用 id 去调用 selectOrdersByUserId 查询订单(可能产生 N+1 问题,需注意)

属性 作用 是否必需
property 主对象中的集合字段名 ✅ 必需
ofType 集合中元素的类型(如 Order ✅ 必需(XML 中强烈建议)
javaType 集合本身的实现类(如 ArrayList ❌ 通常可省略