fix(fin): 激活配置并发行锁保护 FIN-03

- commission_withdrawal_setting/service.go: 激活事务内首步加 FOR UPDATE 行锁,防止并发时出现多条 is_active=true
- wechat_config_store.go: ActivateInTx 激活前同样加行锁保护
This commit is contained in:
2026-03-28 10:38:53 +08:00
parent 0ebb3d75f3
commit bdac4ab7b2
2 changed files with 14 additions and 0 deletions

View File

@@ -11,6 +11,7 @@ import (
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type Service struct {
@@ -47,6 +48,12 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateWithdrawalSettingRe
setting.Updater = currentUserID
err := s.db.Transaction(func(tx *gorm.DB) error {
// 先锁定当前活跃记录,防止并发激活导致多条 is_active=true
var current model.CommissionWithdrawalSetting
tx.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).
Where("is_active = ?", true).
First(&current)
if err := s.commissionWithdrawalSettingStore.DeactivateCurrentWithTx(ctx, tx); err != nil {
return errors.Wrap(errors.CodeInternalError, err, "失效旧配置失败")
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/break/junhong_cmp_fiber/internal/store"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
// WechatConfigStore 微信参数配置数据访问层
@@ -100,6 +101,12 @@ func (s *WechatConfigStore) GetActive(ctx context.Context) (*model.WechatConfig,
// ActivateInTx 在事务内激活指定配置(先停用所有,再激活指定记录)
func (s *WechatConfigStore) ActivateInTx(ctx context.Context, tx *gorm.DB, id uint) error {
// 先锁定当前活跃记录,防止并发激活导致多条 is_active=true
var current model.WechatConfig
tx.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).
Where("is_active = ?", true).
First(&current)
// 先停用所有激活的配置
if err := tx.WithContext(ctx).Model(&model.WechatConfig{}).
Where("is_active = ?", true).