@@ -1120,26 +1120,31 @@ func (s *Service) createOrderWithWalletPayment(ctx context.Context, order *model
}
actualAmount := * order . ActualPaidAmount
// 1. 事务外:检查钱包余额(快速失败)
wallet , err := s . agentWalletStore . GetMainWallet ( ctx , operatorShopID )
if err != nil {
// 事务内:加锁读取钱包 + 余额检查 + 创建订单 + 扣款 + 创建流水 + 激活套餐
// 使用 FOR UPDATE 悲观锁替代乐观锁,避免并发请求因 version 过期导致误报余额不足
err := s . db . WithContext ( ctx ) . Transaction ( func ( tx * gorm . DB ) error {
// 1. 加锁读取钱包,并发请求排队等待,不会冲突
var wallet model . AgentWallet
if err := tx . Set ( "gorm:query_option" , "FOR UPDATE" ) .
Where ( "shop_id = ? AND wallet_type = ?" , operatorShopID , constants . AgentWalletTypeMain ) .
First ( & wallet ) . Error ; err != nil {
if err == gorm . ErrRecordNotFound {
return errors . New ( errors . CodeWalletNotFound , "钱包不存在" )
}
return errors . Wrap ( errors . CodeDatabaseError , err , "查询钱包失败" )
}
// 2. 余额检查(加锁后读到的是最新余额,结果准确)
if wallet . Balance < actualAmount {
return errors . New ( errors . CodeInsufficientBalance , "余额不足" )
}
// 2 . 事务内:创建订单 + 扣款 + 创建流水 + 激活套餐
err = s . db . WithContext ( ctx ) . Transaction ( func ( tx * gorm . DB ) error {
// 2.1 创建订单
// 3 . 创建订单
if err := tx . Create ( order ) . Error ; err != nil {
return errors . Wrap ( errors . CodeDatabaseError , err , "创建订单失败" )
}
// 2.2 创建订单明细
// 4. 创建订单明细
for _ , item := range items {
item . OrderID = order . ID
}
@@ -1147,30 +1152,24 @@ func (s *Service) createOrderWithWalletPayment(ctx context.Context, order *model
return errors . Wrap ( errors . CodeDatabaseError , err , "创建订单明细失败" )
}
// 2.3 扣减钱包余额(乐观锁 )
result := tx . Model ( & model . AgentWallet { } ) .
Where ( "id = ? AND balance >= ? AND version = ?" , wallet . ID , actualAmount , wallet . Version ) .
Updates ( map [ string ] any {
// 5. 扣减钱包余额(FOR UPDATE 已保证串行,无需 version 条件 )
if err := tx . Model ( & wallet ) . Updates ( map [ string ] any {
"balance" : gorm . Expr ( "balance - ?" , actualAmount ) ,
"version" : gorm . Expr ( "version + 1" ) ,
} )
if result . Error != nil {
return errors . Wrap ( errors . CodeDatabaseError , result . Error , "扣减钱包余额失败" )
}
if result . RowsAffected == 0 {
return errors . New ( errors . CodeInsufficientBalance , "余额不足或并发冲突" )
} ) . Error ; err != nil {
return errors . Wrap ( errors . CodeDatabaseError , err , "扣减钱包余额失败" )
}
// 2.4 创建钱包流水
// 6. 创建钱包流水
var relatedShopID * uint
if order . PurchaseRole == model . PurchaseRolePurchaseForSubordinate {
relatedShopID = & buyerShopID
}
if err := s . createWalletTransaction ( ctx , tx , wallet , order , actualAmount , order . PurchaseRole , relatedShopID ) ; err != nil {
if err := s . createWalletTransaction ( ctx , tx , & wallet , order , actualAmount , order . PurchaseRole , relatedShopID ) ; err != nil {
return err
}
// 2.5 激活套餐
// 7. 激活套餐
if err := s . activatePackage ( ctx , tx , order ) ; err != nil {
return err
}