MyBatis一对多查询方式

在 MyBatis 中,一对多查询 是指一个实体对象(如 Order)关联多个子对象(如 OrderItem)。这种关系在数据库中通常通过外键实现,而在 MyBatis 中可以通过 resultMap 的嵌套集合(<collection>)来处理。

以下是对 MyBatis 中一对多查询的详细介绍,包括实现步骤和示例代码。


1. 一对多关系的数据表设计

假设我们有两个表:

  • Orders:存储订单信息。
  • OrderItems:存储订单项信息,每个订单项属于一个订单。

表结构如下:

sql 复制代码
CREATE TABLE Orders (
    order_id INT PRIMARY KEY,
    order_number VARCHAR(50),
    customer_id INT,
    order_date DATE
);

CREATE TABLE OrderItems (
    item_id INT PRIMARY KEY,
    order_id INT,
    product_name VARCHAR(100),
    quantity INT,
    price DECIMAL(10, 2),
    FOREIGN KEY (order_id) REFERENCES Orders(order_id)
);
  • 一个订单(Orders)可以包含多个订单项(OrderItems)。
  • OrderItems 表中的 order_id 是外键,指向 Orders 表的 order_id

2. 实体类设计

在 Java 中,我们需要定义两个实体类来表示这种一对多关系。

Order

java 复制代码
public class Order {
    private int orderId;
    private String orderNumber;
    private int customerId;
    private Date orderDate;
    private List<OrderItem> orderItems; // 一对多关系

    // Getters and Setters
}

OrderItem

java 复制代码
public class OrderItem {
    private int itemId;
    private int orderId;
    private String productName;
    private int quantity;
    private BigDecimal price;

    // Getters and Setters
}

3. MyBatis 实现一对多查询

在 MyBatis 中,一对多查询通常通过 resultMap<collection> 标签来实现。以下是具体步骤。

3.1 定义 resultMap

在 MyBatis 的 Mapper XML 文件中,定义一个 resultMap,使用 <collection> 标签来表示一对多关系。

xml 复制代码
<resultMap id="OrderResultMap" type="Order">
    <!-- 映射 Order 表的基本字段 -->
    <id property="orderId" column="order_id"/>
    <result property="orderNumber" column="order_number"/>
    <result property="customerId" column="customer_id"/>
    <result property="orderDate" column="order_date"/>

    <!-- 一对多关系:Order 包含多个 OrderItem -->
    <collection property="orderItems" ofType="OrderItem">
        <id property="itemId" column="item_id"/>
        <result property="orderId" column="order_id"/>
        <result property="productName" column="product_name"/>
        <result property="quantity" column="quantity"/>
        <result property="price" column="price"/>
    </collection>
</resultMap>
  • property="orderItems":对应 Order 类中的 orderItems 属性。
  • ofType="OrderItem":表示集合中的元素类型是 OrderItem

3.2 编写 SQL 查询

使用 LEFT JOINOrders 表和 OrderItems 表连接起来,确保即使某个订单没有订单项,也能查询到订单信息。

xml 复制代码
<select id="getOrderWithItems" resultMap="OrderResultMap">
    SELECT 
        o.order_id, o.order_number, o.customer_id, o.order_date,
        i.item_id, i.product_name, i.quantity, i.price
    FROM Orders o
    LEFT JOIN OrderItems i ON o.order_id = i.order_id
    WHERE o.order_id = #{orderId}
</select>
  • 使用 LEFT JOIN 是为了确保即使某个订单没有订单项,也能返回订单信息。
  • #{orderId} 是传入的参数。

3.3 Java 接口

在 Java 接口中定义方法:

java 复制代码
public interface OrderMapper {
    Order getOrderWithItems(@Param("orderId") int orderId);
}

4. 查询结果

假设数据库中有以下数据:

Orders

order_id order_number customer_id order_date
1 ORDER001 101 2023-10-01
2 ORDER002 102 2023-10-02

OrderItems

item_id order_id product_name quantity price
1 1 Product A 2 100.00
2 1 Product B 1 50.00
3 2 Product C 3 200.00

调用 getOrderWithItems(1) 后,返回的 Order 对象如下:

java 复制代码
Order {
    orderId: 1,
    orderNumber: "ORDER001",
    customerId: 101,
    orderDate: "2023-10-01",
    orderItems: [
        OrderItem {
            itemId: 1,
            orderId: 1,
            productName: "Product A",
            quantity: 2,
            price: 100.00
        },
        OrderItem {
            itemId: 2,
            orderId: 1,
            productName: "Product B",
            quantity: 1,
            price: 50.00
        }
    ]
}

5. 一对多查询的优化

如果查询结果较大,可能会产生性能问题(如 N+1 查询问题)。可以通过以下方式优化:

5.1 使用 LEFT JOIN 一次性加载

如上面的示例,使用 LEFT JOIN 一次性加载所有数据,避免多次查询。

5.2 分步查询

如果数据量较大,可以使用分步查询(嵌套查询):

xml 复制代码
<resultMap id="OrderResultMap" type="Order">
    <id property="orderId" column="order_id"/>
    <result property="orderNumber" column="order_number"/>
    <result property="customerId" column="customer_id"/>
    <result property="orderDate" column="order_date"/>

    <!-- 分步查询:通过 order_id 查询 OrderItems -->
    <collection property="orderItems" ofType="OrderItem" select="selectOrderItemsByOrderId" column="order_id"/>
</resultMap>

<select id="selectOrderItemsByOrderId" resultType="OrderItem">
    SELECT item_id, order_id, product_name, quantity, price
    FROM OrderItems
    WHERE order_id = #{orderId}
</select>

<select id="getOrderWithItems" resultMap="OrderResultMap">
    SELECT order_id, order_number, customer_id, order_date
    FROM Orders
    WHERE order_id = #{orderId}
</select>
  • select="selectOrderItemsByOrderId":指定嵌套查询的方法。
  • column="order_id":将当前查询的 order_id 作为参数传递给嵌套查询。

6. 总结

  • 一对多查询在 MyBatis 中通过 <collection> 标签实现。
  • 可以使用 LEFT JOIN 一次性加载数据,也可以使用分步查询优化性能。
  • 确保实体类和数据库表的结构正确映射。
  • 通过 resultMap 可以灵活地处理复杂的对象关系。

通过以上方法,你可以在 MyBatis 中轻松实现一对多查询,并灵活应对不同的业务需求。

相关推荐
黑风风1 分钟前
深入理解Spring Boot Starter及如何自定义Starter
java·spring boot·后端
px52133442 分钟前
Solder leakage problems and improvement strategies in electronics manufacturing
java·前端·数据库·pcb工艺
鱼樱前端18 分钟前
Mac M1安装MySQL步骤
java·后端
白衣神棍29 分钟前
【八股文】ArrayList和LinkedList的区别
java
啥都想学的又啥都不会的研究生33 分钟前
Redis设计与实现-数据持久化
java·数据库·redis·笔记·缓存·面试
fly spider40 分钟前
Mybatis语法bug
bug·mybatis
王网aaa2 小时前
堆结构和堆排序
java·算法·排序算法
计算机-秋大田2 小时前
基于Spring Boot的小区疫情购物系统的设计与实现(LW+源码+讲解)
java·vue.js·spring boot·后端·课程设计
loveking62 小时前
SpringBoot调用华为云短信实现发短信功能
java·spring boot·华为云
李长渊哦3 小时前
Spring Boot 约定大于配置:实现自定义配置
java·spring boot·后端