# 订单商品忽略租户隔离查询功能实现 ## 🔍 问题背景 在支付回调处理和商品销量累加过程中,需要查询订单的商品列表: ```java List orderGoodsList = shopOrderGoodsService.getListByOrderId(order.getOrderId()); ``` 但是由于租户隔离机制,可能无法查询到其他租户的订单商品信息,导致销量累加失败。 ## 🎯 解决方案 实现了一个忽略租户隔离的订单商品查询方法`getListByOrderIdIgnoreTenant`,确保能够跨租户查询订单商品信息。 ## 🔧 实现内容 ### 1. ShopOrderGoodsService接口扩展 **文件**: `src/main/java/com/gxwebsoft/shop/service/ShopOrderGoodsService.java` ```java /** * 根据订单ID查询订单商品列表(忽略租户隔离) * @param orderId 订单ID * @return List */ List getListByOrderIdIgnoreTenant(Integer orderId); ``` ### 2. ShopOrderGoodsMapper数据库操作 **文件**: `src/main/java/com/gxwebsoft/shop/mapper/ShopOrderGoodsMapper.java` ```java /** * 根据订单ID查询订单商品列表(忽略租户隔离) * @param orderId 订单ID * @return List */ @InterceptorIgnore(tenantLine = "true") @Select("SELECT * FROM shop_order_goods WHERE order_id = #{orderId} AND deleted = 0") List 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 getListByOrderIdIgnoreTenant(Integer orderId) { try { if (orderId == null) { log.warn("查询订单商品列表参数无效 - 订单ID: {}", orderId); return List.of(); } List 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 orderGoodsList = shopOrderGoodsService.getListByOrderId(order.getOrderId()); // 修改后(忽略租户隔离) final List 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 orderGoodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(order.getOrderId()); for (ShopOrderGoods orderGoods : orderGoodsList) { // 累加商品销量 shopGoodsService.addSaleCount(orderGoods.getGoodsId(), orderGoods.getTotalNum()); } ``` ### 2. 跨租户订单处理 ```java // 需要处理其他租户订单的商品信息 List 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查询,高效获取数据 - **错误处理**: 完善的异常处理和日志记录 现在在支付回调等跨租户业务场景中,可以正确查询到订单商品信息,确保商品销量累加功能正常工作,不会因为租户隔离导致查询失败。