Files
sundynix-plant-be/OPTIMIZATION_REPORT.md
T
2026-02-06 14:44:06 +08:00

3.9 KiB

代码分析与优化建议报告

在分析了项目的核心模块(System, Plant/Claim, Plant/Order)后,发现以下几个在性能、数据一致性及可维护性方面可以优化的地方。

1. 性能优化 (Performance)

1.1 ClaimPlantList 中的 N+1 查询问题

位置: service/plant/claim_plant.go -> ClaimPlantList 问题: 在 ClaimPlantList 函数中,代码在遍历列表 (res) 时,对每一项都执行了一次数据库查询来判断用户是否已领取:

for i := range res {
    // ...
    // 循环内查询!
    err2 := global.DB.Where("claim_plant_id = ? ...", res[i].Id).First(&claim).Error
}

如果每页显示 20 条数据,就会产生 21 次数据库查询。随着数据量增长,接口响应会显著变慢。

优化建议:

  • 批量查询: 先收集列表中所有的 ClaimPlantId
  • 单次查询: 使用 IN 查询一次性获取当前用户关联的所有记录 (WHERE user_id = ? AND claim_plant_id IN (?))。
  • 内存映射: 将查询结果转为 Map,在内存中进行匹配。
  • 效果: 将 N+1 次查询减少为 2 次查询

1.2 订单导出中的高内存占用 (OOM 风险)

位置: service/plant/order.go -> ExportOrder 问题: 该函数使用 db.Find(&orders) 一次性查询符合条件的所有订单。 如果订单量达到 10 万级别,将所有数据加载到切片中会导致内存暴涨,甚至引发 OOM (内存溢出) 崩溃。

优化建议:

  • 流式处理: 使用 Gorm 的 Rows()FindInBatches 分批获取数据。
  • 流式写入: 逐行向 Excel 写入数据,而不是构建好整个大对象后再写入。

2. 数据一致性与并发 (Data Integrity)

2.1 植物认养中的竞态条件 (Race Condition)

位置: service/plant/claim_plant.go -> ClaimPlant 问题: 代码在开启事务前就进行了库存和积分的检查:

// 1. 读库存
if claimPlant.Stock <= 0 { ... }
// 2. 读积分
if personal.PointsCount < claimPlant.Points { ... }
// 3. 开启事务写数据
err = global.DB.Transaction(...)

在高并发场景(如秒杀)下,两个用户可能同时通过 Stock > 0 的检查,但在库存仅剩 1 个时,都会进入事务扣减库存,导致超卖(库存变成 -1)。

优化建议:

  • 悲观锁: 在查询植物和用户积分时使用 clause.Locking{Strength: "UPDATE"} 锁定行。
  • 原子更新: 在 Update 语句中加入条件判断:
    UPDATE claim_plant SET stock = stock - 1 WHERE id = ? AND stock > 0
    
    通过检查 RowsAffected 判断是否扣减成功。

3. 代码质量与可维护性 (Maintainability)

3.1 硬编码的魔法值

位置: service/plant/order.go 问题: 订单状态(1=已支付, 2=退款 等)在代码多处直接使用数字或字符串硬编码。 优化建议:

  • model 包中定义常量或枚举(Enum),并在全局统一使用,避免拼写错误并提高可读性。

3.2 手动事务管理

位置: service/system/sys_user.go -> MiniLogin 问题: 该函数手动使用了 tx.Begin(), tx.Rollback()defer recover(),这种写法容易出错且不简洁。 优化建议:

  • 使用 global.DB.Transaction(func(tx *gorm.DB) error { ... }) 闭包模式。这是 Gorm 推荐的写法,能自动处理 Panic 和错误回滚,代码更清晰。

4. 汇总表

模块 问题 严重程度 类型 建议
Claim 列表 N+1 查询 性能 批量查询 ID
Claim 库存竞态条件 数据安全 悲观锁 / 原子更新
Order 导出全部加载 性能 分批流式处理
Order 魔法值硬编码 可维护性 使用常量常量定义
User 手动事务写法 代码风格 使用 DB.Transaction 闭包