Commit c0dcd970 by 杨树贤

fix(service): 修复协程并发写入竞态并复用Redis连接

parent d44d3bc6
......@@ -47,8 +47,8 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
defer cancel() // 确保函数返回时取消所有协程,释放资源
//抽取自营 或者联营 goods_id
zyService := service.ZiyingService{} //实例化自营查询
lyService := service.LyService{} //实例化联营查询
// 注意:不再在主协程中创建共享的 service 实例,每个 goroutine 内部会创建独立实例,
// 避免并发写入结构体的 Redis 连接字段导致竞态条件
var goodsIdArr []string
if GoodsIdStr == "" {
goodsIdMap := ctx.PostFormMap("goods_id")
......@@ -86,11 +86,12 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
idsToProcess := make([]string, len(zyGoodsId))
copy(idsToProcess, zyGoodsId)
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go func(ctx context.Context, params service.RequestParams, goodsIds []string, ch chan sync.Map) {
defer wg.Done()
zyService.ZyGoodsDetail(ctx, params, goodsIds, ch)
}(ctxWithTimeout, requestParams, idsToProcess, ch)
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go func(ctx context.Context, params service.RequestParams, goodsIds []string, ch chan sync.Map) {
defer wg.Done()
zyService := service.ZiyingService{} // 每个协程创建独立实例,避免竞态
zyService.ZyGoodsDetail(ctx, params, goodsIds, ch)
}(ctxWithTimeout, requestParams, idsToProcess, ch)
zyGoodsId = zyGoodsId[:0]
}
......@@ -107,6 +108,7 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go func(ctx context.Context, params service.RequestParams, goodsIds []string, ch chan sync.Map) {
defer wg.Done()
lyService := service.LyService{} // 每个协程创建独立实例,避免竞态
lyService.LyGoodsDetail(ctx, params, goodsIds, ch)
}(ctxWithTimeout, requestParams, idsToProcess, ch)
......@@ -126,6 +128,7 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go func(ctx context.Context, params service.RequestParams, goodsIds []string, ch chan sync.Map) {
defer wg.Done()
zyService := service.ZiyingService{} // 每个协程创建独立实例,避免竞态
zyService.ZyGoodsDetail(ctx, params, goodsIds, ch)
}(ctxWithTimeout, requestParams, idsToProcess, ch)
}
......@@ -141,6 +144,7 @@ func CommonController(ctx *gin.Context) map[string]interface{} {
// 启动协程,传递独立的 context 和参数,而不是 gin.Context
go func(ctx context.Context, params service.RequestParams, goodsIds []string, ch chan sync.Map) {
defer wg.Done()
lyService := service.LyService{} // 每个协程创建独立实例,避免竞态
lyService.LyGoodsDetail(ctx, params, goodsIds, ch)
}(ctxWithTimeout, requestParams, idsToProcess, ch)
}
......
......@@ -17,6 +17,16 @@ import (
)
type ActivityService struct {
defaultRConn redis.Conn
}
// getRedisConn 获取 Redis 连接。如果结构体上已设置可复用连接则返回该连接(shouldClose=false),
// 否则从连接池获取新连接(shouldClose=true,调用方需负责关闭)。
func (as *ActivityService) getRedisConn(poolName string) (conn redis.Conn, shouldClose bool) {
if poolName == "default_r" && as.defaultRConn != nil {
return as.defaultRConn, false
}
return gredis.Conn(poolName), true
}
/*
......@@ -78,8 +88,10 @@ func (as *ActivityService) GetLabelOp(sku model.LySku) (op int) {
// 获取活动信息,目前是包括促销活动(系数打折)以及满赠活动
func (as *ActivityService) GetActivityData(checkData model.ActivityCheckData) (priceActivity model.PriceActivity, giftActivity model.GiftActivity) {
supplierId := checkData.SupplierId
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := as.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
var redisKey string
//区分猎芯和华云
if checkData.OrgId == 1 {
......@@ -106,8 +118,10 @@ func (as *ActivityService) GetActivityData(checkData model.ActivityCheckData) (p
}
func (as *ActivityService) GetPriceActivity(checkData model.ActivityCheckData, activities []model.Activity) (priceActivity model.PriceActivity) {
redisConn := gredis.Conn("default_r")
defer redisConn.Close()
redisConn, shouldClose := as.getRedisConn("default_r")
if shouldClose {
defer redisConn.Close()
}
var hasActivity bool
nowTimestamp := int(time.Now().Unix())
for _, activity := range activities {
......
......@@ -9,13 +9,25 @@ import (
)
type CustomPrice struct {
defaultRConn redis.Conn
}
// getRedisConn 获取 Redis 连接。如果结构体上已设置可复用连接则返回该连接(shouldClose=false),
// 否则从连接池获取新连接(shouldClose=true,调用方需负责关闭)。
func (sc *CustomPrice) getRedisConn(poolName string) (conn redis.Conn, shouldClose bool) {
if poolName == "default_r" && sc.defaultRConn != nil {
return sc.defaultRConn, false
}
return gredis.Conn(poolName), true
}
// 加上自定义价格的转换
func (sc *CustomPrice) getCustomPriceList(sku model.LySku) (customPriceList []model.CustomPrice, err error) {
//先根据组织获取对应的自定义价格系数
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := sc.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
customPriceRule, _ := redis.String(redisCon.Do("HGET", "cube_custom_price", sku.OrgId))
if customPriceRule=="" {
return customPriceList, nil
......
......@@ -21,6 +21,30 @@ import (
)
type LyService struct {
// 可复用的 Redis 连接,在 LyGoodsDetail 中初始化,for 循环中复用
defaultRConn redis.Conn
spuConn redis.Conn
searchRConn redis.Conn
}
// getRedisConn 获取 Redis 连接。如果结构体上已设置可复用连接则返回该连接(shouldClose=false),
// 否则从连接池获取新连接(shouldClose=true,调用方需负责关闭)。
func (ls *LyService) getRedisConn(poolName string) (conn redis.Conn, shouldClose bool) {
switch poolName {
case "default_r":
if ls.defaultRConn != nil {
return ls.defaultRConn, false
}
case "spu":
if ls.spuConn != nil {
return ls.spuConn, false
}
case "search_r":
if ls.searchRConn != nil {
return ls.searchRConn, false
}
}
return gredis.Conn(poolName), true
}
type Power struct {
......@@ -46,14 +70,20 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
default:
}
redisConn := gredis.Conn("search_r")
redisConnSpu := gredis.Conn("spu")
// 初始化可复用的 Redis 连接,for 循环中复用,避免每次调用子函数都新建/关闭连接
ls.defaultRConn = gredis.Conn("default_r")
ls.searchRConn = gredis.Conn("search_r")
ls.spuConn = gredis.Conn("spu")
// 连接prev_sku MongoDB
prevSkuMongo := mongo.Conn("pre_sku")
defer func() {
prevSkuMongo.Close()
redisConn.Close()
redisConnSpu.Close()
ls.defaultRConn.Close()
ls.searchRConn.Close()
ls.spuConn.Close()
ls.defaultRConn = nil
ls.searchRConn = nil
ls.spuConn = nil
}()
//各种展示条件(从参数中获取,而不是从 gin.Context)
......@@ -75,6 +105,8 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
var spuService SpuService
var activityService ActivityService
spuList := spuService.getSpuList(skuArr)
// 将共享连接传递给子服务,避免在循环中重复创建/关闭连接
activityService.defaultRConn = ls.defaultRConn
GoodsRes := sync.Map{}
for goodsId, skuStr := range skuArr {
......@@ -107,7 +139,7 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
// 根据找到的spu_id去spu的redis中查找
spuIdStr := strconv.FormatInt(prevSku.SpuId, 10)
spuStr, _ := redis.String(redisConnSpu.Do("HGET", "spu", spuIdStr))
spuStr, _ := redis.String(ls.spuConn.Do("HGET", "spu", spuIdStr))
if spuStr == "" {
// 如果spu缓存也没有,保持默认值
GoodsRes.Store(goodsId, false)
......@@ -124,7 +156,7 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
//读取包装字段的缓存(分别是DGK,avnet,mro)
if sku.SupplierId == 7 || sku.SupplierId == 13 || sku.SupplierId == 1688 || sku.SupplierId == 17 {
//sku_raw_map哪里写入(成意写的)
packing, _ := redis.String(redisConnSpu.Do("HGET", "sku_raw_map", goodsId))
packing, _ := redis.String(ls.spuConn.Do("HGET", "sku_raw_map", goodsId))
sku.Packing = gjson.Get(packing, "pack").String()
}
sku = ls.GetGoodsImages(sku, spu)
......@@ -147,7 +179,7 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
//获取品牌名称
brandId := gjson.Get(spu, "brand_id").Int()
brandName, _ := redis.String(redisConn.Do("HGET", "brand", brandId))
brandName, _ := redis.String(ls.searchRConn.Do("HGET", "brand", brandId))
sku.BrandName = brandName
sku.BrandId = brandId
......@@ -218,7 +250,7 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
//这里获取活动价格和活动类型(折扣打折活动)
sku = ls.GetActivity(sku, newCustomer)
priceService := PriceService{}
priceService := PriceService{defaultRConn: ls.defaultRConn}
//这里又有一个判断,如果是非猎芯的,目前只有爱智,通过org_id来判断
//1是猎芯,3是爱智
switch sku.OrgId {
......@@ -229,7 +261,7 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
//获取系数和价格
sku = ls.GetCoefficientAndPrice(sku)
//获取自定义价格后的阶梯价
customPriceService := CustomPrice{}
customPriceService := CustomPrice{defaultRConn: ls.defaultRConn}
sku.CustomPriceList, _ = customPriceService.getCustomPriceList(sku)
sku = priceService.GetActivityPrice(sku)
case 3:
......@@ -256,7 +288,7 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
//获取系数和价格
sku = ls.GetCoefficientAndPrice(sku)
//获取自定义价格后的阶梯价
customPriceService := CustomPrice{}
customPriceService := CustomPrice{defaultRConn: ls.defaultRConn}
sku.CustomPriceList, _ = customPriceService.getCustomPriceList(sku)
//这里还要针对华云的阶梯价进行一次转换,因为要兼容目前华云的使用方式
if sku.OrgId == 3 {
......@@ -321,6 +353,7 @@ func (ls *LyService) LyGoodsDetail(ctx context.Context, params RequestParams, go
//获取标签信息
var TagService TagsService
TagService.defaultRConn = ls.defaultRConn
sku.GoodsTag = TagService.GetLyTags(sku)
//获取关税以及价格转换
......@@ -364,6 +397,7 @@ func (ls *LyService) GetActivity(sku model.LySku, showNewCustomerPrice string) m
NewCustomer: gconv.Int(showNewCustomerPrice),
}
var activityService ActivityService
activityService.defaultRConn = ls.defaultRConn
priceActivity, giftActivity := activityService.GetActivityData(checkData)
if priceActivity.HasActivity {
sku.AcType = 10
......
......@@ -4,7 +4,6 @@ import (
"encoding/json"
"go_sku_server/model"
c "go_sku_server/pkg/common"
"go_sku_server/pkg/gredis"
"go_sku_server/pkg/logger"
_ "go_sku_server/pkg/mongo"
"go_sku_server/service/sorter"
......@@ -81,8 +80,10 @@ func (ls *LyService) GetGoodsClass(sku model.LySku, spu string) model.LySku {
// 获取税务信息,对接税务系统
func (ls *LyService) GetErpTax(goodsName, brandName string) interface{} {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ls.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
key := php2go.Md5(strings.ToUpper(goodsName + brandName))
info, _ := redis.String(redisCon.Do("HGET", "tax_customs_info", key))
data := make(map[string]interface{})
......@@ -97,16 +98,20 @@ func (ls *LyService) GetErpTax(goodsName, brandName string) interface{} {
// 获取联营供应商的名字
func (ls *LyService) GetPoolSupplierName(supplierId int64) (supplierName string) {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ls.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
supplier, _ := redis.String(redisCon.Do("HGET", "supplier", supplierId))
return supplier
}
// 从缓存获取分类
func (ls *LyService) GetCacheClass(classId int64) string {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ls.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
classStr, _ := redis.String(redisCon.Do("HGET", "pool_class_info", classId))
className := gjson.Get(classStr, "class_name").String()
return className
......@@ -128,8 +133,10 @@ type AttrsExtend struct {
// H获取供应链标准品牌
func (ls *LyService) GetScmBrand(brandId int64) (res interface{}) {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ls.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
scmBrandId, _ := redis.Int(redisCon.Do("HGET", "pool_scm_brand_mapping", brandId))
if scmBrandId != 0 {
scmBrandData, err := redis.String(redisCon.Do("HGET", "pool_scm_brand", scmBrandId))
......@@ -148,8 +155,10 @@ func (ls *LyService) GetScmBrand(brandId int64) (res interface{}) {
// 获取新版标准品牌
func (ls *LyService) GetStandardBrand(brandId int64) (standardBrand model.StandardBrand) {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ls.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
standardBrandId, _ := redis.Int(redisCon.Do("HGET", "standard_brand_mapping", brandId))
if standardBrandId != 0 {
standardBrandStr, err := redis.String(redisCon.Do("HGET", "standard_brand", standardBrandId))
......@@ -176,8 +185,10 @@ type ExtendFee struct {
// 获取附加费
func (ls *LyService) GetExtendFee(supplierId int64, canal string) interface{} {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ls.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
if supplierId == 17 {
//为什么专卖的redis键会不一样,专卖的附加费管理在供应商系统,其它的在基石
value, _ := redis.String(redisCon.Do("HGET", "supp_extend_fee", "17."+canal))
......@@ -208,8 +219,10 @@ func (ls *LyService) GetExtendFee(supplierId int64, canal string) interface{} {
// 获取供应商货期
func (ls *LyService) GetDelivery(supplierId int64, canal string) (delivery map[string]string) {
delivery = make(map[string]string)
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ls.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
if canal != "" {
supplierRatio, _ := redis.String(redisCon.Do("HGET", "supp_ratio", canal))
if supplierRatio != "" {
......@@ -275,8 +288,10 @@ func (ls *LyService) GetStock(sku model.LySku) (stock_all, jd_stock int64) {
//如果是寄售的数据(source=12),获取的库存还要减去锁库的库存
if sku.Source == 12 || php2go.InArray(sku.Canal, []string{"L0018319", "L0013521", "L0018562", "L0017764", "L0003270", "L0012413", "L0013521"}) {
//获取总锁库库存
redisCon := gredis.Conn("spu")
defer redisCon.Close()
redisCon, shouldClose := ls.getRedisConn("spu")
if shouldClose {
defer redisCon.Close()
}
stockStr, _ := redis.String(redisCon.Do("HGET", "sku_lock_stock", sku.GoodsId))
lockStock, _ := strconv.ParseInt(stockStr, 10, 64)
if sku.Stock < lockStock {
......@@ -337,8 +352,10 @@ func (ls *LyService) GetCoefficientAndPrice(sku model.LySku) model.LySku {
// L0003270 这个供应商的话
var costTax float64
if sku.Canal == "L0018562" {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ls.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
usdRatio, _ := redis.Float64(redisCon.Do("HGET", "erp_rate", 2))
for index, price := range sku.OriginalPrice {
priceCnTax := c.MulFloat(price.PriceUs, usdRatio)
......@@ -414,8 +431,10 @@ func (ls *LyService) GetCoefficientAndPrice(sku model.LySku) model.LySku {
//去获取各种系数(成本折扣系数,售价组系数,供应商系数)
//这是去找折扣系数
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ls.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
sku = priceService.GetDiscountRatio(sku)
......
......@@ -16,6 +16,16 @@ import (
)
type PriceService struct {
defaultRConn redis.Conn
}
// getRedisConn 获取 Redis 连接。如果结构体上已设置可复用连接则返回该连接(shouldClose=false),
// 否则从连接池获取新连接(shouldClose=true,调用方需负责关闭)。
func (ps *PriceService) getRedisConn(poolName string) (conn redis.Conn, shouldClose bool) {
if poolName == "default_r" && ps.defaultRConn != nil {
return ps.defaultRConn, false
}
return gredis.Conn(poolName), true
}
// 构建专营的阶梯价,现在专营只会存一个简单的成本价,阶梯数量是1,所以我这边要根据专营的阶梯系数去构建具体的阶梯价
......@@ -32,8 +42,10 @@ func (ps *PriceService) GenerateLadderPrice(sku model.LySku) model.LySku {
ratioDataKey = "cost_ladder_price_egt200"
}
//先去获取配置的redis
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ps.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
//找一个标志位,因为默认的全局折扣系数的数据格式和非全局的是不一样的
isDefaultPriceRatio := false
//这里很关键,因为华云也要兼容到猎芯的价格体系,所以缓存里面也有了华云的售价组,但是猎芯存的哈希对应的key是 供应商编码(L002323)
......@@ -467,8 +479,10 @@ func (ps *PriceService) GenerateLadderPrice(sku model.LySku) model.LySku {
// 获取折扣系数(通用)
func (ps *PriceService) GetDiscountRatio(sku model.LySku) model.LySku {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ps.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
discountRatioRedisKey := "magic_cube_channel_discount_daigou"
discountRatioDefaultRedisKey := "magic_cube_channel_discount_default_daigou"
......@@ -564,8 +578,10 @@ func (ps *PriceService) GetDiscountRatio(sku model.LySku) model.LySku {
// 获取售价组(代购)
func (ps PriceService) GetPriceRatio(sku model.LySku) (model.LySku, []model.PriceRatio) {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ps.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
//找一个标志位,因为默认的全局折扣系数的数据格式和非全局的是不一样的
isDefaultPriceRatio := false
......@@ -726,10 +742,10 @@ func (ps *PriceService) TransformSpecialSupplierPrice(sku model.LySku) model.LyS
return sku
}
//去redis获取价格
redisCon := gredis.Conn("default_r")
defer func() {
redisCon.Close()
}()
redisCon, shouldClose := ps.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
usRatio, _ := redis.Float64(redisCon.Do("HGET", "erp_rate", 2))
var currency int
var currencyConfig string
......@@ -931,8 +947,10 @@ func (ps *PriceService) GetActivityPrice(sku model.LySku) model.LySku {
// compare_price_ratio
func (ps *PriceService) GetComparePrice(sku model.LySku) model.LySku {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ps.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
//判断是否存在
compareData, _ := redis.String(redisCon.Do("HGET", "compare_price_ratio", sku.GoodsId))
if compareData == "" {
......
......@@ -2,7 +2,6 @@ package service
import (
"go_sku_server/model"
"go_sku_server/pkg/gredis"
"go_sku_server/pkg/logger"
"go_sku_server/pkg/mongo"
"go_sku_server/pkg/vars"
......@@ -56,10 +55,10 @@ func (ss *LyService) getStockInfo(supplierId, oldGoodsId int64) interface{} {
// 获取新的在途库存
func (ss *LyService) getOnwayStock(goodsId string) int {
redisConn := gredis.Conn("spu")
defer func() {
redisConn.Close()
}()
redisConn, shouldClose := ss.getRedisConn("spu")
if shouldClose {
defer redisConn.Close()
}
onWayStockStr, _ := redis.String(redisConn.Do("HGET", "sku_onway_stock", goodsId))
if onWayStockStr == "" {
......@@ -71,10 +70,10 @@ func (ss *LyService) getOnwayStock(goodsId string) int {
// 获取新的在途库存
func (ss *LyService) getLimitStock(goodsId string) (has bool, stock int) {
redisConn := gredis.Conn("search_r")
defer func() {
redisConn.Close()
}()
redisConn, shouldClose := ss.getRedisConn("search_r")
if shouldClose {
defer redisConn.Close()
}
limitStockStr, _ := redis.String(redisConn.Do("HGET", "limit_stock", goodsId))
if limitStockStr == "" {
......
......@@ -13,6 +13,16 @@ import (
//标签相关服务,包括goods_label
type TagsService struct {
defaultRConn redis.Conn
}
// getRedisConn 获取 Redis 连接。如果结构体上已设置可复用连接则返回该连接(shouldClose=false),
// 否则从连接池获取新连接(shouldClose=true,调用方需负责关闭)。
func (ts *TagsService) getRedisConn(poolName string) (conn redis.Conn, shouldClose bool) {
if poolName == "default_r" && ts.defaultRConn != nil {
return ts.defaultRConn, false
}
return gredis.Conn(poolName), true
}
// 当天发货标签
......@@ -20,8 +30,10 @@ const TagZiyingSku = 4
// 获取Spu的属性
func (ts *TagsService) GetTags(skuId string, selfSupplierType int64) (goodsTags model.GoodsTag) {
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ts.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
goodsTagsStr, _ := redis.String(redisCon.Do("HGET", "goods_tag", skuId))
goodsLabel := ""
//goods_tag
......@@ -62,8 +74,10 @@ func (ts *TagsService) GetTags(skuId string, selfSupplierType int64) (goodsTags
// 获取联营tags
func (ts *TagsService) GetLyTags(sku model.LySku) (goodsTags model.GoodsTag) {
skuId := sku.GoodsId
redisCon := gredis.Conn("default_r")
defer redisCon.Close()
redisCon, shouldClose := ts.getRedisConn("default_r")
if shouldClose {
defer redisCon.Close()
}
goodsTagsStr, _ := redis.String(redisCon.Do("HGET", "goods_tag", skuId))
goodsLabel := ""
//goods_tag
......
......@@ -10,12 +10,37 @@ import (
"strings"
"sync"
"github.com/gomodule/redigo/redis"
"github.com/iancoleman/orderedmap"
"github.com/syyongx/php2go"
"github.com/tidwall/gjson"
)
type ZiyingService struct {
// 可复用的 Redis 连接,在 ZyGoodsDetail 中初始化,for 循环中复用
defaultRConn redis.Conn
spuConn redis.Conn
searchRConn redis.Conn
}
// getRedisConn 获取 Redis 连接。如果结构体上已设置可复用连接则返回该连接(shouldClose=false),
// 否则从连接池获取新连接(shouldClose=true,调用方需负责关闭)。
func (qs *ZiyingService) getRedisConn(poolName string) (conn redis.Conn, shouldClose bool) {
switch poolName {
case "default_r":
if qs.defaultRConn != nil {
return qs.defaultRConn, false
}
case "spu":
if qs.spuConn != nil {
return qs.spuConn, false
}
case "search_r":
if qs.searchRConn != nil {
return qs.searchRConn, false
}
}
return gredis.Conn(poolName), true
}
/*
......@@ -44,12 +69,17 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
default:
}
redisConn := gredis.Conn("search_r")
redisConnSpu := gredis.Conn("spu")
// 初始化可复用的 Redis 连接,for 循环中复用
qs.defaultRConn = gredis.Conn("default_r")
qs.searchRConn = gredis.Conn("search_r")
qs.spuConn = gredis.Conn("spu")
defer func() {
//wg.Done();
redisConn.Close()
redisConnSpu.Close()
qs.defaultRConn.Close()
qs.searchRConn.Close()
qs.spuConn.Close()
qs.defaultRConn = nil
qs.searchRConn = nil
qs.spuConn = nil
}()
skuArr := gredis.Hmget("search_r", "Self_SelfGoods", goodsIds) //批量获取商品详情
......@@ -113,13 +143,13 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
classId2 := gjson.Get(info, "class_id2").Int()
classId1Name := ""
if classId1 > 0 {
classId1Info, _ := gredis.String(redisConn.Do("HGET", "Self_SelfClassInfo", classId1))
classId1Info, _ := gredis.String(qs.searchRConn.Do("HGET", "Self_SelfClassInfo", classId1))
classId1Name = gjson.Get(classId1Info, "class_name").String()
}
classId2Name := ""
if classId2 > 0 {
classId2Info, _ := gredis.String(redisConn.Do("HGET", "Self_SelfClassInfo", classId2))
classId2Info, _ := gredis.String(qs.searchRConn.Do("HGET", "Self_SelfClassInfo", classId2))
classId2Name = gjson.Get(classId2Info, "class_name").String()
}
......@@ -131,13 +161,15 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
var spuClassId2 int64
var brandName string
var activityService ActivityService
activityService.defaultRConn = qs.defaultRConn
if spuId != 0 {
spuStr, _ := gredis.String(redisConnSpu.Do("HGET", "spu", spuId))
spuStr, _ := gredis.String(qs.spuConn.Do("HGET", "spu", spuId))
brandId = gjson.Get(spuStr, "brand_id").Int()
spuClassId1 = gjson.Get(spuStr, "class_id1").Int()
spuClassId2 = gjson.Get(spuStr, "class_id2").Int()
brandName, _ = gredis.String(redisConn.Do("HGET", "brand", brandId))
brandName, _ = gredis.String(qs.searchRConn.Do("HGET", "brand", brandId))
var ly LyService
ly.defaultRConn = qs.defaultRConn
standardBrand = ly.GetStandardBrand(brandId)
}
......@@ -185,7 +217,7 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
A.Set("stock", 0) //默认库存为0
dbStock := gjson.Get(info, "stock").Int() //当前db库存
if dbStock > 0 {
lockStock := SkuLockNum(goodsId) //当前锁库库存
lockStock := qs.SkuLockNum(goodsId) //当前锁库库存
stockG := dbStock - lockStock //当前可购买库存
if stockG > 0 {
A.Set("actual_stock", dbStock) //锁定库存
......@@ -209,7 +241,7 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
//查询品牌名称(作废,现在改成读联营的品牌库,之前有关联自营商品到spu_id)
brand_id := gjson.Get(info, "brand_id").Int()
brand_info, _ := gredis.String(redisConn.Do("HGET", "Self_Brand", brand_id))
brand_info, _ := gredis.String(qs.searchRConn.Do("HGET", "Self_Brand", brand_id))
A.Set("brand_name", gjson.Get(brand_info, "brand_name").String())
A.Set("brand_id", brand_id)
......@@ -218,7 +250,7 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
supplier_id := gjson.Get(info, "supplier_id").String()
supplier_name := ""
if supplier_id != "" {
supplierInfo, _ := gredis.String(redisConn.Do("HGET", "Self_SelfSupplierInfo", supplier_id))
supplierInfo, _ := gredis.String(qs.searchRConn.Do("HGET", "Self_SelfSupplierInfo", supplier_id))
supplier_name = gjson.Get(supplierInfo, "supplier_name").String()
}
A.Set("supplier_name", supplier_name)
......@@ -227,7 +259,7 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
goodsUnit := gjson.Get(info, "goods_unit").String()
goodsUnitName := ""
if goodsUnit != "" {
goodsUnitName, _ = gredis.String(redisConn.Do("HGET", "Self_Unit", goodsUnit))
goodsUnitName, _ = gredis.String(qs.searchRConn.Do("HGET", "Self_Unit", goodsUnit))
}
A.Set("goods_unit_name", goodsUnitName)
......@@ -235,14 +267,14 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
packing := gjson.Get(info, "packing").String()
packingName := ""
if packing != "" {
packingName, _ = gredis.String(redisConn.Do("HGET", "Self_Unit", packing))
packingName, _ = gredis.String(qs.searchRConn.Do("HGET", "Self_Unit", packing))
}
A.Set("packing_name", packingName) //
//mpq包装名称
mpqUnitName := ""
if packing != "" {
mpqUnitName, _ = gredis.String(redisConn.Do("HGET", "Self_UnitAlias", packing))
mpqUnitName, _ = gredis.String(qs.searchRConn.Do("HGET", "Self_UnitAlias", packing))
}
A.Set("mpq_unit_name", mpqUnitName) //
......@@ -250,7 +282,7 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
img := gjson.Get(info, "goods_images").String()
goodsImages := ""
if img != "" {
goodsImages, _ = gredis.String(redisConn.Do("HGET", "Self_SelfGoodsSource", img))
goodsImages, _ = gredis.String(qs.searchRConn.Do("HGET", "Self_SelfGoodsSource", img))
}
image := gjson.Get(goodsImages, "url").String()
image = strings.Replace(image, "http://img.ichunt.com", "https://img.ichunt.com", 1)
......@@ -260,7 +292,7 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
pdf := gjson.Get(info, "pdf").String()
if pdf != "" {
pdf, _ = gredis.String(redisConn.Do("HGET", "Self_SelfGoodsSource", pdf))
pdf, _ = gredis.String(qs.searchRConn.Do("HGET", "Self_SelfGoodsSource", pdf))
}
pdf = gjson.Get(pdf, "url").String()
pdf = strings.Replace(pdf, "http://img.ichunt.com", "https://img.ichunt.com", 1)
......@@ -270,7 +302,7 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
A.Set("scm_brand_name", gjson.Get(info, "scm_brand_name").String()) //
//处理系数
ratio, _ := gredis.String(redisConn.Do("HGET", "zy_ratio_sku", goodsId))
ratio, _ := gredis.String(qs.searchRConn.Do("HGET", "zy_ratio_sku", goodsId))
var PriceAcXi float64 = 0 //系数
if ratio != "" {
PriceAcXi = gjson.Get(ratio, "price_ac").Float()
......@@ -322,7 +354,7 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
}
//处理限额
goodsQuota, _ := gredis.String(redisConn.Do("HGET", "Self_goods_quota", goodsId))
goodsQuota, _ := gredis.String(qs.searchRConn.Do("HGET", "Self_goods_quota", goodsId))
if goodsQuota != "" {
A.Set("is_quota", 1)
A.Set("quota_num", gjson.Get(goodsQuota, "num").Int())
......@@ -355,6 +387,7 @@ func (qs *ZiyingService) ZyGoodsDetail(ctx context.Context, params RequestParams
//获取标签信息
var tagService TagsService
tagService.defaultRConn = qs.defaultRConn
A.Set("goods_tag", tagService.GetTags(goodsId, gjson.Get(info, "self_supplier_type").Int()))
A.Set("canal", "L0003270") //自营写死编码
......
......@@ -3,7 +3,6 @@ package service
import (
"go_sku_server/model"
"go_sku_server/pkg/common"
"go_sku_server/pkg/gredis"
"strconv"
"github.com/gomodule/redigo/redis"
......@@ -17,10 +16,12 @@ import (
/*
获取自营锁库数量
*/
func SkuLockNum(goodsId string) int64 {
func (qs *ZiyingService) SkuLockNum(goodsId string) int64 {
//获取总锁库库存
redisCon := gredis.Conn("spu")
defer redisCon.Close()
redisCon, shouldClose := qs.getRedisConn("spu")
if shouldClose {
defer redisCon.Close()
}
stockStr, _ := redis.String(redisCon.Do("HGET", "sku_lock_stock", goodsId))
lockStock, _ := strconv.ParseInt(stockStr, 10, 64)
return lockStock
......@@ -67,12 +68,14 @@ func (qs *ZiyingService) GetActivity(skuInfo string) (priceActivity model.PriceA
//去判断是否有活动(促销打折活动和满赠活动)
var standardBrandId int
spuId := gjson.Get(skuInfo, "spu_id").String()
redisCon := gredis.Conn("default_r")
redisConSpu := gredis.Conn("spu")
defer func() {
redisCon.Close()
redisConSpu.Close()
}()
redisCon, shouldClose1 := qs.getRedisConn("default_r")
redisConSpu, shouldClose2 := qs.getRedisConn("spu")
if shouldClose1 {
defer redisCon.Close()
}
if shouldClose2 {
defer redisConSpu.Close()
}
spuStr, _ := redis.String(redisConSpu.Do("HGET", "spu", spuId))
if spuStr == "" {
......@@ -90,6 +93,7 @@ func (qs *ZiyingService) GetActivity(skuInfo string) (priceActivity model.PriceA
GoodsName: gjson.Get(skuInfo, "goods_name").String(),
}
var activityService ActivityService
activityService.defaultRConn = qs.defaultRConn
priceActivity, giftActivity = activityService.GetActivityData(checkData)
return
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment