draft
This commit is contained in:
90
backend/internal/repository/sequence.go
Normal file
90
backend/internal/repository/sequence.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"pay-bridge/internal/model"
|
||||
)
|
||||
|
||||
// SequenceRepository 序列数据访问
|
||||
type SequenceRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewSequenceRepository(db *gorm.DB) *SequenceRepository {
|
||||
return &SequenceRepository{db: db}
|
||||
}
|
||||
|
||||
// IncrAndGet 原子自增并返回新值(行级锁)
|
||||
func (r *SequenceRepository) IncrAndGet(ctx context.Context, appID string, seqType model.SeqType) (uint64, error) {
|
||||
var seq model.OrderSequence
|
||||
|
||||
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
// 加行锁读取
|
||||
if err := tx.Set("gorm:query_option", "FOR UPDATE").
|
||||
Where("app_id = ? AND seq_type = ?", appID, seqType).
|
||||
First(&seq).Error; err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
// 自动初始化序列
|
||||
prefix := defaultPrefix(seqType)
|
||||
seq = model.OrderSequence{
|
||||
AppID: appID,
|
||||
SeqType: seqType,
|
||||
Prefix: prefix,
|
||||
CurrentValue: 0,
|
||||
Step: 1,
|
||||
}
|
||||
if err := tx.Create(&seq).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
// 重新加锁读
|
||||
return tx.Set("gorm:query_option", "FOR UPDATE").
|
||||
Where("app_id = ? AND seq_type = ?", appID, seqType).
|
||||
First(&seq).Error
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 自增
|
||||
newVal := seq.CurrentValue + uint64(seq.Step)
|
||||
if err := r.db.WithContext(ctx).Model(&model.OrderSequence{}).
|
||||
Where("id = ?", seq.ID).
|
||||
Update("current_value", newVal).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return newVal, nil
|
||||
}
|
||||
|
||||
func defaultPrefix(t model.SeqType) string {
|
||||
switch t {
|
||||
case model.SeqTypeTrade:
|
||||
return "PAY"
|
||||
case model.SeqTypeRefund:
|
||||
return "REF"
|
||||
case model.SeqTypeSharing:
|
||||
return "SHA"
|
||||
default:
|
||||
return "ORD"
|
||||
}
|
||||
}
|
||||
|
||||
// GetPrefix 获取序列前缀
|
||||
func (r *SequenceRepository) GetPrefix(ctx context.Context, appID string, seqType model.SeqType) (string, error) {
|
||||
var seq model.OrderSequence
|
||||
err := r.db.WithContext(ctx).Where("app_id = ? AND seq_type = ?", appID, seqType).First(&seq).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fmt.Sprintf("%s", defaultPrefix(seqType)), nil
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return seq.Prefix, nil
|
||||
}
|
||||
Reference in New Issue
Block a user