表配置了逻辑删除后,删除并不是真正的 DELETE,而是把标记字段更新为已删除。主表和明细如果分开处理,很容易留下一边可见、一边不可见的数据。
一、服务层统一删除
@Transactional(rollbackFor = Exception.class)
public boolean removeWithDetails(Long orderId) {
if (!removeById(orderId)) {
return false;
}
orderDetailService.remove(new LambdaQueryWrapper<OrderDetail>()
.eq(OrderDetail::getOrderId, orderId));
return true;
}
Controller 只传订单 ID,不关心主明细结构。
二、返回 false 和抛异常是两种语义
订单不存在时返回 false,由接口转换成“资源不存在”;数据库操作失败时抛异常,由事务回滚并进入全局错误处理。二者不要混成同一种处理方式。
三、逻辑删除同样要事务
主表标记删除成功后,如果明细更新失败,事务回滚,两边恢复一致。没有事务时,接口可能返回成功,但数据状态已经裂开。
四、查询也要遵守同一假设
订单列表查询不带明细,单个订单查询聚合明细。后续如果做统计报表,必须记得逻辑删除字段,否则会把历史删除数据重新算进去。
五、经验总结
逻辑删除解决的是审计和恢复需求,不是让删除变得不用考虑一致性。主从结构一旦出现,删除永远是一个业务事务。