以下是一个完整的 用户 → 订单 → 订单明细 → 商品 的 三级嵌套一对多 案例,包含数据库设计、Java 实体类和 MyBatis 实现:
场景描述
- 用户可以有多个订单(一对多)
- 每个订单可以包含多个订单明细(一对多)
- 每个订单明细关联一个商品(多对一)
数据库表结构
sql
-- 用户表
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL
);
-- 订单表
CREATE TABLE order (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
order_no VARCHAR(20),
FOREIGN KEY (user_id) REFERENCES user(id)
);
-- 商品表
CREATE TABLE product (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2)
);
-- 订单明细表(连接订单和商品)
CREATE TABLE order_item (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
FOREIGN KEY (order_id) REFERENCES order(id),
FOREIGN KEY (product_id) REFERENCES product(id)
);
Java 实体类
java
// User.java
public class User {
private Integer id;
private String username;
private List<Order> orders; // 一级一对多
// getters/setters
}
// Order.java
public class Order {
private Integer id;
private String orderNo;
private List<OrderItem> items; // 二级一对多
// getters/setters
}
// OrderItem.java
public class OrderItem {
private Integer id;
private Integer quantity;
private Product product; // 三级多对一
// getters/setters
}
// Product.java
public class Product {
private Integer id;
private String name;
private BigDecimal price;
// getters/setters
}
MyBatis 实现方案
方案一:联表查询(适合数据量小的情况)
xml
<!-- UserMapper.xml -->
<resultMap id="userDetailMap" type="User">
<id property="id" column="user_id"/>
<result property="username" column="username"/>
<!-- 一级一对多:用户 → 订单 -->
<collection property="orders" ofType="Order">
<id property="id" column="order_id"/>
<result property="orderNo" column="order_no"/>
<!-- 二级一对多:订单 → 订单明细 -->
<collection property="items" ofType="OrderItem">
<id property="id" column="item_id"/>
<result property="quantity" column="quantity"/>
<!-- 三级多对一:订单明细 → 商品 -->
<association property="product" javaType="Product">
<id property="id" column="product_id"/>
<result property="name" column="product_name"/>
<result property="price" column="price"/>
</association>
</collection>
</collection>
</resultMap>
<select id="findUserWithDetails" resultMap="userDetailMap">
SELECT
u.id AS user_id,
u.username,
o.id AS order_id,
o.order_no,
oi.id AS item_id,
oi.quantity,
p.id AS product_id,
p.name AS product_name,
p.price
FROM user u
LEFT JOIN order o ON u.id = o.user_id
LEFT JOIN order_item oi ON o.id = oi.order_id
LEFT JOIN product p ON oi.product_id = p.id
WHERE u.id = #{userId}
</select>
方案二:嵌套查询(适合大数据量,支持延迟加载)
xml
<!-- UserMapper.xml -->
<resultMap id="userMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<!-- 一级嵌套查询 -->
<collection
property="orders"
column="id"
ofType="Order"
select="findOrdersByUserId"/>
</resultMap>
<select id="findUserWithDetails" resultMap="userMap">
SELECT * FROM user WHERE id = #{userId}
</select>
<!-- 二级查询:订单及明细 -->
<resultMap id="orderMap" type="Order">
<id property="id" column="id"/>
<result property="orderNo" column="order_no"/>
<!-- 二级嵌套查询 -->
<collection
property="items"
column="id"
ofType="OrderItem"
select="findItemsByOrderId"/>
</resultMap>
<select id="findOrdersByUserId" resultMap="orderMap">
SELECT * FROM order WHERE user_id = #{userId}
</select>
<!-- 三级查询:订单明细及商品 -->
<resultMap id="itemMap" type="OrderItem">
<id property="id" column="id"/>
<result property="quantity" column="quantity"/>
<!-- 三级嵌套查询 -->
<association
property="product"
column="product_id"
javaType="Product"
select="findProductById"/>
</resultMap>
<select id="findItemsByOrderId" resultMap="itemMap">
SELECT * FROM order_item WHERE order_id = #{orderId}
</select>
<!-- 商品查询 -->
<select id="findProductById" resultType="Product">
SELECT * FROM product WHERE id = #{productId}
</select>
执行效果
查询结果会生成如下嵌套结构:
java
User{
id=1,
username="张三",
orders=[
Order{
id=1001,
orderNo="20230815001",
items=[
OrderItem{
id=5001,
quantity=2,
product=Product{id=101, name="手机", price=2999.00}
},
OrderItem{
id=5002,
quantity=1,
product=Product{id=102, name="耳机", price=399.00}
}
]
},
Order{
id=1002,
orderNo="20230816002",
items=[
OrderItem{
id=5003,
quantity=3,
product=Product{id=103, name="充电宝", price=199.00}
}
]
}
]
}
性能优化建议
-
联表查询方案 • 优点:单次查询获取全部数据 • 缺点:结果集会有重复数据(用户和订单信息会重复出现在每条订单明细记录中) • 适用场景:数据量较小的系统
-
嵌套查询方案 • 优点:按需加载,支持延迟加载 • 缺点:产生 1+N+M 次查询(用户查询1次 + 订单查询N次 + 商品查询M次) • 优化方法:配置批量加载
xml<!-- mybatis-config.xml --> <settings> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings>
关键点总结
-
标签嵌套规则 • 一级一对多:
<collection>
嵌套在<resultMap>
• 二级一对多:<collection>
嵌套在父级<collection>
• 多对一关系:使用<association>
-
字段别名规范
sql-- 联表查询时使用明确别名 u.id AS user_id, o.id AS order_id, oi.id AS item_id
-
参数传递 • 嵌套查询中通过
column
属性传递参数时,确保子查询方法的参数名与传递的列名一致
通过这种多级嵌套方案,可以处理任意深度的对象关联关系,建议根据实际业务复杂度选择最合适的实现方式。