package repoimpl import ( "context" "encoding/json" "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 (p *ProductRepoImpl) DB(ctx context.Context) *gorm.DB { return p.db.DB(ctx).WithContext(ctx).Model(model.Product{}) } func (r *ProductRepoImpl) GetByPNO(ctx context.Context, PNO string) (*bo.ProductBo, error) { var item *model.Product c := vo.ProductQueryKey.BuildCache([]string{PNO}) 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)) } 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{PNO}) 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.getByPNO(ctx, item, PNO) b, err := json.Marshal(item) if err == nil { r.rdb.Rdb.Set(ctx, c.Key, string(b), c.TTL) } return err }) if err != nil { return nil, err } return r.ToBo(item), err } func (r *ProductRepoImpl) getByPNO(ctx context.Context, item *model.Product, PNO string) (*model.Product, error) { db := r.DB(ctx) tx := db.Where(model.Product{ProductNo: PNO}).Find(&item) if tx.Error != nil { 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 }