不需要。用 MyBatis-Plus 完全可以实现,而且更优雅。 一般不需要写原生 JOIN 的 SQL。因为一般的联查和串联查询性能差距不是很大。
不需要。用 MyBatis-Plus 完全可以实现,而且更优雅。 不需要写原生 JOIN 的 SQL。
推荐做法:MyBatis-Plus 关联查询
你可以用 Service 层封装关联查询,或者直接用 MyBatis-Plus 的自动注入功能。以下是两种方案:
方案一:Service 层封装(推荐,逻辑清晰)
在 AfterSalesItemService中写一个方法,完成数据组装:
VO 对象示例:
@Data
public class AfterSalesItemVO extends AfterSalesItem {
// 商品快照信息
private Long skuId;
private String skuName;
private String specInfo;
private String mainImage;
private BigDecimal unitPrice;
private BigDecimal payAmount;
// 还可以根据需要加入当前商品信息
private Sku currentSkuInfo;
}
方案二:使用 MyBatis-Plus 的自动注入(更简洁)
在实体类上使用 @TableField的 select = false配合自定义查询:
@Data
@TableName("after_sales_item")
public class AfterSalesItem {
private Long id;
private Long afterSalesId;
private Long orderItemId;
private Integer quantity;
// 商品快照信息(非数据库字段,查询时自动注入)
@TableField(exist = false)
private String skuName;
@TableField(exist = false)
private String specInfo;
@TableField(exist = false)
private BigDecimal payAmount;
// ... 其他字段
}
在 Mapper 中写自定义查询(用 MyBatis 的 XML 或注解,现在一般不推荐这样写,不好维护):
public interface AfterSalesItemMapper extends BaseMapper<AfterSalesItem> {
/**
* 联查订单商品快照
*/
@Select("SELECT asi.*, oi.sku_name, oi.spec_info, oi.pay_amount " +
"FROM after_sales_item asi " +
"LEFT JOIN order_item oi ON asi.order_item_id = oi.id " +
"WHERE asi.after_sales_id = #{afterSalesId}")
List<AfterSalesItem> selectWithSnapshot(@Param("afterSalesId") Long afterSalesId);
}
性能对比与选择建议
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Service 层封装 | 1. 逻辑清晰,易于维护和调试 2. 可以利用 MyBatis-Plus 的缓存、分页等特性 3. 便于后续加缓存 |
1. 需要手动组装 2. 有两次查询(售后商品 + 订单快照) |
绝大多数场景,推荐使用 |
| MyBatis-Plus 联查 | 1. 一次查询,理论上更快 2. 代码简洁 |
1. 破坏了 MyBatis-Plus 的简单性 2. 复杂查询难以维护 3. 无法利用 MP 的高级特性 |
简单、固定的关联查询 |
实际开发中的最佳实践
1.用 Service 层封装为主,保持代码清晰。
2.利用批量查询:如方案一中的 orderItemService.listByIds()就是批量查询,避免 N+1 问题。
3.考虑分页:如果售后商品可能很多,在第一步查询售后商品时就可以加分页。
4.使用缓存:OrderItem是历史快照,不会变更,非常适合用缓存(如 Redis)存储,进一步提高查询性能。
5.使用异步多线程:若有多表查询方案,可使用异步多线程方式实现提高速度。(多表写入不推荐,无法跟踪异常)
本文固定连接:https://code.zuifengyun.com/2026/04/3622.html,转载须征得作者授权。