Files
java-10561/docs/订单商品忽略租户隔离查询功能.md
2025-09-06 11:58:18 +08:00

240 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 订单商品忽略租户隔离查询功能实现
## 🔍 问题背景
在支付回调处理和商品销量累加过程中,需要查询订单的商品列表:
```java
List<ShopOrderGoods> orderGoodsList = shopOrderGoodsService.getListByOrderId(order.getOrderId());
```
但是由于租户隔离机制,可能无法查询到其他租户的订单商品信息,导致销量累加失败。
## 🎯 解决方案
实现了一个忽略租户隔离的订单商品查询方法`getListByOrderIdIgnoreTenant`,确保能够跨租户查询订单商品信息。
## 🔧 实现内容
### 1. ShopOrderGoodsService接口扩展
**文件**: `src/main/java/com/gxwebsoft/shop/service/ShopOrderGoodsService.java`
```java
/**
* 根据订单ID查询订单商品列表忽略租户隔离
* @param orderId 订单ID
* @return List<ShopOrderGoods>
*/
List<ShopOrderGoods> getListByOrderIdIgnoreTenant(Integer orderId);
```
### 2. ShopOrderGoodsMapper数据库操作
**文件**: `src/main/java/com/gxwebsoft/shop/mapper/ShopOrderGoodsMapper.java`
```java
/**
* 根据订单ID查询订单商品列表忽略租户隔离
* @param orderId 订单ID
* @return List<ShopOrderGoods>
*/
@InterceptorIgnore(tenantLine = "true")
@Select("SELECT * FROM shop_order_goods WHERE order_id = #{orderId} AND deleted = 0")
List<ShopOrderGoods> selectListByOrderIdIgnoreTenant(@Param("orderId") Integer orderId);
```
**关键特性**:
-`@InterceptorIgnore(tenantLine = "true")` - 忽略租户隔离
-`@Select`注解直接执行SQL查询
- ✅ 只过滤已删除的记录,不过滤租户
### 3. ShopOrderGoodsServiceImpl业务实现
**文件**: `src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderGoodsServiceImpl.java`
```java
@Override
public List<ShopOrderGoods> getListByOrderIdIgnoreTenant(Integer orderId) {
try {
if (orderId == null) {
log.warn("查询订单商品列表参数无效 - 订单ID: {}", orderId);
return List.of();
}
List<ShopOrderGoods> orderGoodsList = baseMapper.selectListByOrderIdIgnoreTenant(orderId);
log.info("忽略租户隔离查询订单商品成功 - 订单ID: {}, 商品数量: {}",
orderId, orderGoodsList != null ? orderGoodsList.size() : 0);
return orderGoodsList != null ? orderGoodsList : List.of();
} catch (Exception e) {
log.error("忽略租户隔离查询订单商品异常 - 订单ID: {}", orderId, e);
return List.of();
}
}
```
**功能特性**:
- ✅ 参数验证 - 检查orderId的有效性
- ✅ 异常处理 - 捕获并记录异常信息
- ✅ 详细日志 - 记录查询结果和关键信息
- ✅ 安全返回 - 异常时返回空列表而不是null
### 4. ShopOrderServiceImpl集成
**文件**: `src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java`
```java
// 修改前(受租户隔离影响)
final List<ShopOrderGoods> orderGoodsList = shopOrderGoodsService.getListByOrderId(order.getOrderId());
// 修改后(忽略租户隔离)
final List<ShopOrderGoods> orderGoodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(order.getOrderId());
```
## 🔄 调用流程
```
支付成功回调
ShopOrderServiceImpl.updateByOutTradeNo()
handlePaymentSuccess()
updateGoodsSales()
shopOrderGoodsService.getListByOrderIdIgnoreTenant() [忽略租户隔离]
获取订单商品列表
updateSingleGoodsSales() [累加每个商品销量]
```
## 🎯 核心优势
### 1. 租户隔离绕过
- ✅ 使用`@InterceptorIgnore(tenantLine = "true")`忽略租户隔离
- ✅ 可以查询任意租户的订单商品信息
- ✅ 确保跨租户业务逻辑正常执行
### 2. 数据完整性
- ✅ 查询完整的订单商品信息
- ✅ 包含商品ID、名称、数量等关键信息
- ✅ 与普通查询返回相同的数据结构
### 3. 错误处理
- ✅ 完善的参数验证
- ✅ 异常捕获和日志记录
- ✅ 安全的返回值处理
### 4. 性能优化
- ✅ 直接SQL查询避免复杂的条件构建
- ✅ 单次查询获取所有订单商品
- ✅ 减少数据库交互次数
## 🧪 测试验证
**测试文件**: `src/test/java/com/gxwebsoft/shop/service/ShopOrderGoodsIgnoreTenantTest.java`
### 测试用例
1. **基本功能测试** - 验证忽略租户隔离查询订单商品
2. **参数验证测试** - 验证null值和无效ID的处理
3. **跨租户查询测试** - 验证查询不同租户订单商品的能力
4. **批量查询性能测试** - 验证批量查询的性能表现
### 运行测试
```bash
# 运行单个测试类
mvn test -Dtest=ShopOrderGoodsIgnoreTenantTest
# 运行特定测试方法
mvn test -Dtest=ShopOrderGoodsIgnoreTenantTest#testGetListByOrderIdIgnoreTenant
```
## 📋 对比分析
| 方法 | 租户隔离 | 使用场景 | 安全性 |
|-----|---------|----------|--------|
| `getListByOrderId()` | ✅ 受限制 | 普通业务查询 | 高 |
| `getListByOrderIdIgnoreTenant()` | ❌ 忽略 | 跨租户业务处理 | 中等 |
## 🔍 使用场景
### 1. 支付回调处理
```java
// 在支付回调中需要查询订单商品进行销量累加
List<ShopOrderGoods> orderGoodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(order.getOrderId());
for (ShopOrderGoods orderGoods : orderGoodsList) {
// 累加商品销量
shopGoodsService.addSaleCount(orderGoods.getGoodsId(), orderGoods.getTotalNum());
}
```
### 2. 跨租户订单处理
```java
// 需要处理其他租户订单的商品信息
List<ShopOrderGoods> crossTenantOrderGoods = shopOrderGoodsService.getListByOrderIdIgnoreTenant(otherTenantOrderId);
if (!crossTenantOrderGoods.isEmpty()) {
// 执行跨租户业务逻辑
}
```
## 📊 监控和日志
### 成功日志
```
忽略租户隔离查询订单商品成功 - 订单ID: 123, 商品数量: 3
```
### 失败日志
```
查询订单商品列表参数无效 - 订单ID: null
忽略租户隔离查询订单商品异常 - 订单ID: 123
```
### 业务日志
```java
log.info("订单商品详情 - ID: {}, 商品ID: {}, 商品名称: {}, 数量: {}",
orderGoods.getId(), orderGoods.getGoodsId(),
orderGoods.getGoodsName(), orderGoods.getTotalNum());
```
## 🔒 安全考虑
### 1. 使用场景限制
- 仅在确实需要跨租户查询时使用
- 主要用于内部业务逻辑,不暴露给前端
- 避免在普通的CRUD操作中使用
### 2. 数据安全
- 确保调用方有合理的业务需求
- 记录关键操作日志
- 避免敏感信息泄露
### 3. 性能考虑
- 在高并发场景下谨慎使用
- 考虑添加缓存机制
- 监控查询性能
## ✅ 验证清单
- [x] ShopOrderGoodsService接口添加getListByOrderIdIgnoreTenant方法
- [x] ShopOrderGoodsMapper添加selectListByOrderIdIgnoreTenant方法
- [x] 使用@InterceptorIgnore忽略租户隔离
- [x] ShopOrderGoodsServiceImpl实现业务逻辑
- [x] ShopOrderServiceImpl使用新方法
- [x] 添加完善的参数验证和异常处理
- [x] 创建测试用例验证功能
- [x] 添加详细的日志记录
## 🎉 总结
订单商品忽略租户隔离查询功能已完整实现,具备以下特性:
- **跨租户能力**: 忽略租户隔离,可查询任意租户的订单商品
- **数据完整性**: 返回完整的订单商品信息
- **安全可控**: 仅在特定业务场景使用,不暴露给前端
- **性能优化**: 直接SQL查询高效获取数据
- **错误处理**: 完善的异常处理和日志记录
现在在支付回调等跨租户业务场景中,可以正确查询到订单商品信息,确保商品销量累加功能正常工作,不会因为租户隔离导致查询失败。