Files
java-10561/docs/商品销量累加功能实现.md
2025-09-06 11:58:18 +08:00

236 lines
7.1 KiB
Markdown
Raw Permalink 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.

# 商品销量累加功能实现
## 🎯 功能概述
实现了商品销售数量的累加功能,确保在支付成功后能够正确更新商品的销量统计。使用`@InterceptorIgnore`注解忽略租户隔离,确保跨租户的商品销量能够正确更新。
## 🔧 实现内容
### 1. ShopGoodsService接口扩展
**文件**: `src/main/java/com/gxwebsoft/shop/service/ShopGoodsService.java`
```java
/**
* 累加商品销售数量
* 忽略租户隔离,确保能更新成功
*
* @param goodsId 商品ID
* @param saleCount 累加的销售数量
* @return 是否更新成功
*/
boolean addSaleCount(Integer goodsId, Integer saleCount);
```
### 2. ShopGoodsMapper数据库操作
**文件**: `src/main/java/com/gxwebsoft/shop/mapper/ShopGoodsMapper.java`
```java
/**
* 累加商品销售数量
* 使用@InterceptorIgnore忽略租户隔离确保能更新成功
*
* @param goodsId 商品ID
* @param saleCount 累加的销售数量
* @return 影响的行数
*/
@InterceptorIgnore(tenantLine = "true")
@Update("UPDATE shop_goods SET sales = IFNULL(sales, 0) + #{saleCount} WHERE goods_id = #{goodsId}")
int addSaleCount(@Param("goodsId") Integer goodsId, @Param("saleCount") Integer saleCount);
```
**关键特性**:
-`@InterceptorIgnore(tenantLine = "true")` - 忽略租户隔离
-`IFNULL(sales, 0)` - 处理销量字段为null的情况
- ✅ 原子性操作 - 直接在数据库层面进行累加
### 3. ShopGoodsServiceImpl业务实现
**文件**: `src/main/java/com/gxwebsoft/shop/service/impl/ShopGoodsServiceImpl.java`
```java
@Override
public boolean addSaleCount(Integer goodsId, Integer saleCount) {
try {
if (goodsId == null || saleCount == null || saleCount <= 0) {
log.warn("累加商品销量参数无效 - 商品ID: {}, 销量: {}", goodsId, saleCount);
return false;
}
int affectedRows = baseMapper.addSaleCount(goodsId, saleCount);
boolean success = affectedRows > 0;
if (success) {
log.info("商品销量累加成功 - 商品ID: {}, 累加数量: {}, 影响行数: {}", goodsId, saleCount, affectedRows);
} else {
log.warn("商品销量累加失败 - 商品ID: {}, 累加数量: {}, 影响行数: {}", goodsId, saleCount, affectedRows);
}
return success;
} catch (Exception e) {
log.error("累加商品销量异常 - 商品ID: {}, 累加数量: {}", goodsId, saleCount, e);
return false;
}
}
```
**功能特性**:
- ✅ 参数验证 - 检查goodsId和saleCount的有效性
- ✅ 异常处理 - 捕获并记录异常信息
- ✅ 详细日志 - 记录操作结果和关键信息
- ✅ 返回值明确 - 明确返回操作是否成功
### 4. ShopOrderServiceImpl集成
**文件**: `src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java`
```java
/**
* 累计单个商品的销量
* 使用新的addSaleCount方法忽略租户隔离确保更新成功
*/
private void updateSingleGoodsSales(ShopOrderGoods orderGoods) {
try {
if (orderGoods.getGoodsId() == null || orderGoods.getTotalNum() == null || orderGoods.getTotalNum() <= 0) {
log.warn("商品销量累计参数无效 - 商品ID{},购买数量:{}",
orderGoods.getGoodsId(), orderGoods.getTotalNum());
return;
}
// 使用新的addSaleCount方法忽略租户隔离
boolean updated = shopGoodsService.addSaleCount(orderGoods.getGoodsId(), orderGoods.getTotalNum());
if (updated) {
log.info("商品销量累计成功 - 商品ID{},商品名称:{},购买数量:{}",
orderGoods.getGoodsId(), orderGoods.getGoodsName(), orderGoods.getTotalNum());
} else {
log.warn("商品销量累计失败 - 商品ID{},商品名称:{},购买数量:{}",
orderGoods.getGoodsId(), orderGoods.getGoodsName(), orderGoods.getTotalNum());
}
} catch (Exception e) {
log.error("累计单个商品销量异常 - 商品ID{},商品名称:{},购买数量:{}",
orderGoods.getGoodsId(), orderGoods.getGoodsName(), orderGoods.getTotalNum(), e);
}
}
```
## 🔄 调用流程
```
支付成功回调
ShopOrderServiceImpl.updateByOutTradeNo()
handlePaymentSuccess()
updateGoodsSales()
updateSingleGoodsSales()
ShopGoodsService.addSaleCount()
ShopGoodsMapper.addSaleCount() [忽略租户隔离]
数据库更新销量
```
## 🎯 核心优势
### 1. 租户隔离处理
- ✅ 使用`@InterceptorIgnore(tenantLine = "true")`忽略租户隔离
- ✅ 确保跨租户商品销量能够正确更新
- ✅ 避免因租户隔离导致的更新失败
### 2. 数据一致性
- ✅ 原子性操作 - 在数据库层面直接累加
- ✅ 避免并发问题 - 不需要先查询再更新
- ✅ 处理null值 - 使用IFNULL确保计算正确
### 3. 错误处理
- ✅ 完善的参数验证
- ✅ 异常捕获和日志记录
- ✅ 明确的返回值指示操作结果
### 4. 性能优化
- ✅ 单条SQL语句完成累加
- ✅ 避免查询-修改-更新的多步操作
- ✅ 减少数据库交互次数
## 🧪 测试验证
**测试文件**: `src/test/java/com/gxwebsoft/shop/service/ShopGoodsSalesTest.java`
### 测试用例
1. **基本功能测试** - 验证正常的销量累加
2. **参数验证测试** - 验证各种无效参数的处理
3. **批量累加测试** - 验证多次累加的正确性
### 运行测试
```bash
# 运行单个测试类
mvn test -Dtest=ShopGoodsSalesTest
# 运行特定测试方法
mvn test -Dtest=ShopGoodsSalesTest#testAddSaleCount
```
## 📋 使用示例
```java
// 在支付成功后累加商品销量
@Resource
private ShopGoodsService shopGoodsService;
// 累加销量
Integer goodsId = 123;
Integer purchaseCount = 5;
boolean success = shopGoodsService.addSaleCount(goodsId, purchaseCount);
if (success) {
log.info("商品销量累加成功");
} else {
log.error("商品销量累加失败");
}
```
## 🔍 监控和日志
### 成功日志
```
商品销量累加成功 - 商品ID: 123, 累加数量: 5, 影响行数: 1
```
### 失败日志
```
商品销量累加失败 - 商品ID: 123, 累加数量: 5, 影响行数: 0
累加商品销量参数无效 - 商品ID: null, 销量: 5
```
### 异常日志
```
累加商品销量异常 - 商品ID: 123, 累加数量: 5
```
## ✅ 验证清单
- [x] ShopGoodsService接口添加addSaleCount方法
- [x] ShopGoodsMapper添加数据库操作方法
- [x] 使用@InterceptorIgnore忽略租户隔离
- [x] ShopGoodsServiceImpl实现业务逻辑
- [x] ShopOrderServiceImpl集成新方法
- [x] 添加完善的参数验证和异常处理
- [x] 创建测试用例验证功能
- [x] 添加详细的日志记录
## 🎉 总结
商品销量累加功能已完整实现,具备以下特性:
- **可靠性**: 忽略租户隔离,确保更新成功
- **一致性**: 原子性操作,避免并发问题
- **健壮性**: 完善的错误处理和参数验证
- **可观测性**: 详细的日志记录和监控
- **可测试性**: 完整的测试用例覆盖
现在支付成功后,商品销量能够正确累加,不会因为租户隔离或其他问题导致更新失败。