diff --git a/internal/service/energy_service.go b/internal/service/energy_service.go index 3b89efd..2a37a54 100644 --- a/internal/service/energy_service.go +++ b/internal/service/energy_service.go @@ -63,6 +63,9 @@ func (s *EnergyService) Energize(energizerID uint, postID uint, amount int) (int } var expGained int + var needExpUpdate bool + var expToday time.Time + var expTotal int err := s.db.Transaction(func(tx *gorm.DB) error { txRepo := s.repo.WithTx(tx) @@ -153,7 +156,7 @@ func (s *EnergyService) Energize(energizerID uint, postID uint, amount int) (int return fmt.Errorf("创建被赋能者流水失败: %w", err) } - // 10. 计算经验值(溢出截断) + // 10. 计算经验值(溢出截断)—— 在事务内读取以保证一致性 loc, _ := time.LoadLocation("Asia/Shanghai") now := time.Now().In(loc) today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, loc) @@ -173,30 +176,38 @@ func (s *EnergyService) Energize(energizerID uint, postID uint, amount int) (int expGain = expRoom } - // 11. 增加经验 + 更新每日经验汇总 - if expGain > 0 { - if s.expSvc != nil { - _, _, err = s.expSvc.AddExp(energizerID, expGain) - if err != nil { - return fmt.Errorf("增加经验失败: %w", err) - } - } - - newSummary := &model.DailyExpSummary{ - UserID: energizerID, - Date: today, - ExpEarned: currentDaily + expGain, - } - if err := txRepo.UpsertDailyExp(newSummary); err != nil { - return fmt.Errorf("更新每日经验汇总失败: %w", err) - } - } - expGained = expGain + if expGain > 0 { + needExpUpdate = true + expToday = today + expTotal = currentDaily + expGain + } return nil }) + if err != nil { + return 0, err + } - return expGained, err + // 11. 事务提交后,在事务外增加经验 + 更新每日汇总 + // 必须在事务外执行:LevelService.AddExp 也操作 users 表, + // 若在事务内调用会造成连接池不同连接间行锁死锁。 + if needExpUpdate { + if s.expSvc != nil { + if _, _, err := s.expSvc.AddExp(energizerID, expGained); err != nil { + return expGained, fmt.Errorf("赋能成功,但增加经验失败: %w", err) + } + } + newSummary := &model.DailyExpSummary{ + UserID: energizerID, + Date: expToday, + ExpEarned: expTotal, + } + if err := s.repo.UpsertDailyExp(newSummary); err != nil { + return expGained, fmt.Errorf("赋能成功,但更新经验汇总失败: %w", err) + } + } + + return expGained, nil } // CheckInEnergy 签到获得域能(LV0 用户不调用此方法)