fix: 修复文章赋能死锁导致请求卡住的问题
- 事务内操作 users 表(扣域能)后,调用 LevelService.AddExp 也操作同一 users 表行,不同 DB 连接间产生行锁死锁 - 将 AddExp 和 UpsertDailyExp 移出事务,等事务提交释放行锁后再执行 - 经验计算仍在事务内读取以保证一致性
This commit is contained in:
@ -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 用户不调用此方法)
|
||||
|
||||
Reference in New Issue
Block a user