voucher/internal/data/repoimpl/product.go

107 lines
2.5 KiB
Go

package repoimpl
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/go-kratos/kratos/v2/log"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
err2 "voucher/api/err"
"voucher/internal/biz/bo"
"voucher/internal/biz/repo"
"voucher/internal/biz/vo"
"voucher/internal/data"
"voucher/internal/data/model"
"voucher/internal/pkg/lock"
)
// ProductRepoImpl .
type ProductRepoImpl struct {
Base[model.Product, bo.ProductBo]
db *data.Db
rdb *data.Rdb
}
// NewProductRepoImpl .
func NewProductRepoImpl(db *data.Db, rdb *data.Rdb) repo.ProductRepo {
return &ProductRepoImpl{db: db, rdb: rdb}
}
func (r *ProductRepoImpl) GetByProductNo(ctx context.Context, productNo string) (*bo.ProductBo, error) {
c := vo.ProductQueryKey.BuildCache([]string{productNo})
cacheValue, err := r.rdb.Rdb.Get(ctx, c.Key).Result()
if err != nil && err != redis.Nil {
return nil, fmt.Errorf(fmt.Sprintf("获取商品缓存异常,%s:%v", c.Key, err))
}
var item *model.Product
if len(cacheValue) > 0 {
if err = json.Unmarshal([]byte(cacheValue), &item); err != nil {
return nil, err
}
return r.ToBo(item), nil
}
cl := vo.ProductQueryLockKey.BuildCache([]string{productNo})
err = lock.NewMutex(r.rdb.Rdb, cl.TTL).Lock(ctx, cl.Key, func(ctx context.Context) error {
cacheValue, err = r.rdb.Rdb.Get(ctx, c.Key).Result()
if err != nil && err != redis.Nil {
return fmt.Errorf(fmt.Sprintf("二次获取商品缓存异常,%s:%v", c.Key, err))
}
if len(cacheValue) > 0 {
return json.Unmarshal([]byte(cacheValue), &item)
}
item, err = r.getByProductNo(ctx, item, productNo)
if err != nil {
return err
}
b, err3 := json.Marshal(item)
if err3 != nil {
return err3
}
return r.rdb.Rdb.Set(ctx, c.Key, string(b), c.TTL).Err()
})
if err != nil {
return nil, err
}
return r.ToBo(item), err
}
func (r *ProductRepoImpl) getByProductNo(ctx context.Context, item *model.Product, productNo string) (*model.Product, error) {
db := r.db.DB(ctx).WithContext(ctx).Model(model.Product{})
tx := db.Where(model.Product{ProductNo: productNo}).First(&item)
if tx.Error != nil {
if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
return nil, err2.ErrorDbNotFound("商品数据不存在")
}
sqlDB, _ := db.DB()
log.Warnf("product当前打开连接数:%d,空闲连接数:%d", sqlDB.Stats().OpenConnections, sqlDB.Stats().Idle)
return nil, fmt.Errorf("product db fail %w", tx.Error)
}
if tx.RowsAffected == 0 {
return nil, err2.ErrorDbNotFound("商品数据不存在")
}
return item, nil
}