package front import ( "encoding/json" "errors" "fmt" "github.com/gin-gonic/gin" "github.com/go-redis/redis" "github.com/satori/go.uuid" "gorm.io/gorm" "strconv" "sync" "time" "worktest/pkg/controller" "worktest/pkg/model" "worktest/pkg/redistab" ) type ListReq struct { Title string `json:"'title'"` UserId uint `json:"'userId'"` } type DetailReq struct { ID uint UserId uint `json:"'userId'"` } var synMysqlToRedisLock sync.RWMutex var buych = make(chan int,1) func MysqlList(c *gin.Context) { var req ListReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } var list []*model.Product model.DB.Model(&model.Product{}).Find(&list) fmt.Println("2--------", redistab.RedisClient) controller.Success(c, list) return } func NormalMysqlBuy(c *gin.Context) { var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } err := model.DB.Transaction(func(tx *gorm.DB) error { var obj *model.Product if err := model.DB.Model(&model.Product{}).First(&obj, req.ID).Error; err != nil { return err } if obj.StockSize <= 0 { return errors.New("库存不足") } //生成订单 productOrder := &model.ProductOrder{ ProductID: req.ID, UserId: req.UserId, } if err := model.DB.Model(&model.ProductOrder{}).Create(&productOrder).Error; err != nil { return err } //扣除库存 if err := model.DB.Model(&model.Product{}).Where(&model.Product{ID: req.ID}). UpdateColumn("stock_size", gorm.Expr("stock_size - 1")).Error;err != nil{ return err } return nil }) if err != nil { controller.Error(c, err.Error()) return } controller.Success(c, nil) return } func MysqlBuy(c *gin.Context) { var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } err := model.DB.Transaction(func(tx *gorm.DB) error { var obj *model.Product if err := tx.Model(&model.Product{}).First(&obj, req.ID).Error; err != nil { return err } if obj.StockSize <= 0 { return errors.New("库存不足") } //生成订单 productOrder := &model.ProductOrder{ ProductID: req.ID, UserId: req.UserId, } if err := tx.Model(&model.ProductOrder{}).Create(&productOrder).Error; err != nil { return err } //扣除库存 if err := tx.Model(&model.Product{}).Where(&model.Product{ID: req.ID}). UpdateColumn("stock_size", gorm.Expr("stock_size - 1")).Error;err != nil{ return err } return nil }) if err != nil { controller.Error(c, err.Error()) return } controller.Success(c, nil) return } //GoroutineBuy redis事务购买 func GoroutineBuy(c *gin.Context) { var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } stackKey:=redistab.GetProductStockSize(req.ID) orderKey:=redistab.GetProductOrderList(req.ID) saleKey:=redistab.GetProductSaleNum(req.ID) select { case buych <-1: // 从ch中读取到数据 default: controller.Error(c, "请稍后购买") return } defer func() { <-buych }() n, err := redistab.RedisClient.Get(stackKey).Int64() if err != nil && err != redis.Nil { controller.Error(c, err.Error()) return } if n<=0 { controller.Error(c, "库存不足") return } //扣除库存 redistab.RedisClient.Decr(stackKey) //增加订单 redistab.RedisClient.LPush(orderKey,fmt.Sprintf(`{"productId":%d,"userId":%d}`,req.ID,req.UserId)) //记录已售出 redistab.RedisClient.Incr(saleKey) if err != nil { controller.Error(c, err.Error()) return } controller.Success(c, nil) return } //RedisLockBuy redis事务购买 func RedisLockBuy(c *gin.Context) { var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } stackKey:=redistab.GetProductStockSize(req.ID) orderKey:=redistab.GetProductOrderList(req.ID) saleKey:=redistab.GetProductSaleNum(req.ID) lockKey:=redistab.GetProductLockRedisKey(req.ID) uuidStr := getUuid() //两个锁 isSet, err :=redistab.RedisClient.SetNX(lockKey,uuidStr,30*time.Second).Result() if err != nil{ controller.Error(c, err.Error()) return } if !isSet { controller.Error(c, "请稍后重试") return } /* defer func(lockKey,uuidStr string) { temp,err:= redistab.RedisClient.Get(lockKey).Result() if err == nil && temp == uuidStr{//存在可能释放了别人的锁 redistab.RedisClient.Del(lockKey) } }(lockKey,uuidStr) */ //lua脚本释放 defer func(lockKey,uuidStr string) { luaUnLockStr := "if redis.call('get',KEYS[1]) == ARGV[1] then " + "return redis.call('del',KEYS[1]) else return 0 end" //return jedis.eval(luaScript, Collections.singletonList(key), Collections.singletonList(value)).equals(1L); script := redis.NewScript(luaUnLockStr) // Call the Lua script and pass the key as an argument result, err := script.Run(redistab.RedisClient, []string{lockKey},uuidStr).Result() fmt.Println(result,err) }(lockKey,uuidStr) n, err := redistab.RedisClient.Get(stackKey).Int64() if err != nil && err != redis.Nil { controller.Error(c, err.Error()) return } if n<=0 { controller.Error(c, "库存不足") return } //扣除库存 redistab.RedisClient.Decr(stackKey) //增加订单 redistab.RedisClient.LPush(orderKey,fmt.Sprintf(`{"productId":%d,"userId":%d}`,req.ID,req.UserId)) //记录已售出 redistab.RedisClient.Incr(saleKey) if err != nil { controller.Error(c, err.Error()) return } controller.Success(c, nil) return } //RealRedisTxBuy redis事务购买 func RealRedisTxBuy(c *gin.Context) { } //RedisTxBuy redis事务购买 func RedisTxBuy(c *gin.Context) { var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } stackKey:=redistab.GetProductStockSize(req.ID) orderKey:=redistab.GetProductOrderList(req.ID) saleKey:=redistab.GetProductSaleNum(req.ID) err := redistab.RedisClient.Watch(func(tx *redis.Tx) error { n, err := tx.Get(stackKey).Int64() fmt.Println("2--------",n,err) if err != nil { return err } if n <= 0 { return errors.New("库存不足") } _, err = tx.TxPipelined( func(pipeliner redis.Pipeliner) error { v,err:=pipeliner.Decr(stackKey).Result() fmt.Println() fmt.Println("1----------",v,err) //增加订单 pipeliner.LPush(orderKey,fmt.Sprintf(`{"productId":%d,"userId":%d}`,req.ID,req.UserId)) //记录已售出 pipeliner.Incr(saleKey) return nil }) return err }, stackKey) fmt.Println() fmt.Println() fmt.Println() fmt.Println() if err != nil { fmt.Println(err.Error()) controller.Error(c, err.Error()) return } fmt.Println("2--------", redistab.RedisClient) controller.Success(c, nil) return } //RedisTxBuy redis事务购买 func ChainBuy(c *gin.Context) { var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } stackKey:=redistab.GetProductStockSize(req.ID) orderKey:=redistab.GetProductOrderList(req.ID) saleKey:=redistab.GetProductSaleNum(req.ID) redistab.RedisClient.Watch(func(tx *redis.Tx) error { n, err := tx.Get(stackKey).Int64() if err != nil && err != redis.Nil { return err } if n<=0 { return errors.New("库存不足") } //扣除库存 tx.Decr(stackKey) //增加订单 tx.LPush(orderKey,fmt.Sprintf(`{"productId":%d,"userId":%d}`,req.ID,req.UserId)) //记录已售出 tx.Incr(saleKey) /* _, err = tx.Pipelined(func(pipe redis.Pipeliner) error { pipe.Set(key, strconv.FormatInt(n+1, 10), 0) return nil }) */ return err }, stackKey) err := model.DB.Transaction(func(tx *gorm.DB) error { var obj *model.Product if err := model.DB.Model(&model.Product{}).First(&obj, req.ID).Error; err != nil { return err } if obj.StockSize <= 0 { return errors.New("库存不足") } //生成订单 productOrder := &model.ProductOrder{ ProductID: req.ID, UserId: req.UserId, } if err := model.DB.Model(&model.ProductOrder{}).Create(&productOrder).Error; err != nil { return err } //扣除库存 model.DB.Model(&model.Product{}).Where(&model.Product{ID: req.ID}).UpdateColumn("stock_size", gorm.Expr("stock_size - 1")) return nil }) if err != nil { controller.Error(c, err.Error()) return } fmt.Println("2--------", redistab.RedisClient) controller.Success(c, "购买成功") return } func RedisList(c *gin.Context) { var req ListReq var productKeys []string var productList []*model.Product if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } //vals, err :=redistab.RedisClient.ZRange(redistab.GetProductIdZet(),0,-1).Result() //fmt.Println("1--------",vals,err) //vals, err =redistab.RedisClient.ZRange(redistab.GetProductIdZet(),0,1).Result() //fmt.Println("1--------",vals,err) //vals, err =redistab.RedisClient.ZRange(redistab.GetProductIdZet(),3,5).Result() //fmt.Println("1--------",vals,err) /* //hash单个 result, err := client.HGetAll("user").Result() if err != nil { panic(err) } user := User{ Name: result["name"], Email: result["email"], Age: strconv.Atoi(result["age"]), } //hash单个 keys := []string{"user:0", "user:1"} results, err := client.MGet(keys...).Result() if err != nil { panic(err) } var users []User for _, result := range results { data, ok := result.(map[string]interface{}) if ok { user := User{ Name: data["name"].(string), Email: data["email"].(string), Age: int(data["age"].(int64)), } users = append(users, user) } } */ vals, err :=redistab.RedisClient.ZRevRange(redistab.GetProductIdZet(),0,-1).Result() fmt.Println("1--------",vals,err) for _,t:= range vals{ tempId, err := strconv.Atoi(t) if err == nil{ productKeys = append(productKeys,redistab.GetProductDetail(uint(tempId))) } } // 输出结果 values,err:=redistab.RedisClient.MGet(productKeys...).Result() if err != nil { controller.Error(c, err.Error()) return } if len(values) <= 0 { controller.Error(c, "") return } for _,t := range values{ var temp *model.Product if t != nil{ err = json.Unmarshal([]byte(t.(string)),&temp) if err != nil{ continue } productList = append(productList,temp) } } controller.Success(c, productList) //统计人获取的次数 return } func RecList(c *gin.Context) { var req ListReq var productKeys []string var productList []*model.Product if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } //vals, err :=redistab.RedisClient.ZRange(redistab.GetProductIdZet(),0,-1).Result() //fmt.Println("1--------",vals,err) //vals, err =redistab.RedisClient.ZRange(redistab.GetProductIdZet(),0,1).Result() //fmt.Println("1--------",vals,err) //vals, err =redistab.RedisClient.ZRange(redistab.GetProductIdZet(),3,5).Result() //fmt.Println("1--------",vals,err) vals, err :=redistab.RedisClient.ZRevRange(redistab.GetProductIdZet(),0,-1).Result() fmt.Println("1--------",vals,err) for _,t:= range vals{ tempId, err := strconv.Atoi(t) if err == nil{ productKeys = append(productKeys,redistab.GetProductDetail(uint(tempId))) } } // 输出结果 values,err:=redistab.RedisClient.MGet(productKeys...).Result() if err != nil { controller.Error(c, err.Error()) return } if len(values) <= 0 { controller.Error(c, "") return } for _,t := range values{ var temp *model.Product if t != nil{ err = json.Unmarshal([]byte(t.(string)),&temp) if err != nil{ continue } productList = append(productList,temp) } } controller.Success(c, productList) //统计人获取的次数 return } func MysqlDetail(c *gin.Context) { var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } var productObj *model.Product if err := model.DB.Model(&model.Product{}).First(&productObj, req.ID).Error; err != nil { controller.Error(c, err.Error()) return } controller.Success(c, productObj) return } func RedisDetail(c *gin.Context) { var productObj *model.Product var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } v, err := redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result() //无缓存 则去mysql同步数据 if err != nil { var tempObj *model.Product if err := model.DB.Model(&model.Product{}).First(&tempObj, req.ID).Error; err != nil { controller.Error(c, err.Error()) return } b, err := json.Marshal(tempObj) if err != nil { controller.Error(c, err.Error()) return } v, err = redistab.RedisClient.Set(redistab.GetProductDetail(req.ID), string(b), 0).Result() fmt.Println("1---------", v, err) if err != nil { controller.Error(c, err.Error()) return } v, _ = redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result() } err = json.Unmarshal([]byte(v), &productObj) if err != nil { controller.Error(c, err.Error()) return } controller.Success(c, productObj) return } func RedisDetailLock(c *gin.Context) { var productObj *model.Product var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } v, err := redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result() //无缓存 则去mysql同步数据 if err != nil { synMysqlToRedisLock.Lock() defer synMysqlToRedisLock.Lock() var tempObj *model.Product if err := model.DB.Model(&model.Product{}).First(&tempObj, req.ID).Error; err != nil { controller.Error(c, err.Error()) return } b, err := json.Marshal(tempObj) if err != nil { controller.Error(c, err.Error()) return } v, err = redistab.RedisClient.Set(redistab.GetProductDetail(req.ID), string(b), 0).Result() fmt.Println("1---------", v, err) if err != nil { controller.Error(c, err.Error()) return } v, _ = redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result() } err = json.Unmarshal([]byte(v), &productObj) if err != nil { controller.Error(c, err.Error()) return } controller.Success(c, productObj) return } func RedisDetailBitMap(c *gin.Context) { var productObj *model.Product var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } v, err := redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result() //bitmap bit, err := redistab.RedisClient.GetBit(redistab.GetProductBitMap(), int64(req.ID)).Result() fmt.Println("2----------", bit, err) if bit == 0 { //不存在 controller.Error(c, "非法数据") return } //无缓存 则去mysql同步数据 if err != nil { synMysqlToRedisLock.Lock() defer synMysqlToRedisLock.Lock() var tempObj *model.Product if err := model.DB.Model(&model.Product{}).First(&tempObj, req.ID).Error; err != nil { controller.Error(c, err.Error()) return } b, err := json.Marshal(tempObj) if err != nil { controller.Error(c, err.Error()) return } v, err = redistab.RedisClient.Set(redistab.GetProductDetail(req.ID), string(b), 0).Result() fmt.Println("1---------", v, err) if err != nil { controller.Error(c, err.Error()) return } v, _ = redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result() } err = json.Unmarshal([]byte(v), &productObj) if err != nil { controller.Error(c, err.Error()) return } //增加统计,增加去重统计 该商品的DAU _, _ = redistab.RedisClient.PFAdd(redistab.GetProductDetailLogCount(req.ID)).Result() controller.Success(c, productObj) return } func RedisCountProduct(c *gin.Context) { var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } //增加统计,增加去重统计 该商品的DAU _ = &redis.BitCount{ Start: 1, End: 1, } b, _ := redistab.RedisClient.BitCount(redistab.GetProductBitMap(), nil).Result() controller.Success(c, b) return } func RedisDetailBitMapCount1(c *gin.Context) { var productObj *model.Product var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } v, err := redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result() //bitmap bit, err := redistab.RedisClient.GetBit(redistab.GetProductBitMap(), int64(req.ID)).Result() fmt.Println("2----------", bit, err) if bit == 0 { //不存在 controller.Error(c, "非法数据") return } //无缓存 则去mysql同步数据 if err != nil { synMysqlToRedisLock.Lock() defer synMysqlToRedisLock.Lock() var tempObj *model.Product if err := model.DB.Model(&model.Product{}).First(&tempObj, req.ID).Error; err != nil { controller.Error(c, err.Error()) return } b, err := json.Marshal(tempObj) if err != nil { controller.Error(c, err.Error()) return } v, err = redistab.RedisClient.Set(redistab.GetProductDetail(req.ID), string(b), 0).Result() fmt.Println("1---------", v, err) if err != nil { controller.Error(c, err.Error()) return } v, _ = redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result() } err = json.Unmarshal([]byte(v), &productObj) if err != nil { controller.Error(c, err.Error()) return } //增加统计,增加去重统计 该商品的DAU _, _ = redistab.RedisClient.PFAdd(redistab.GetProductDetailLogCount(req.ID)).Result() controller.Success(c, productObj) return } func RedisDetailBitMapCount(c *gin.Context) { var productObj *model.Product var req DetailReq if err := c.ShouldBind(&req); err != nil { controller.Error(c, err.Error()) return } v, err := redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result() //bitmap bit, err := redistab.RedisClient.GetBit(redistab.GetProductBitMap(), int64(req.ID)).Result() fmt.Println("2----------", bit, err) if bit == 0 { //不存在 controller.Error(c, "非法数据") return } //无缓存 则去mysql同步数据 if err != nil { synMysqlToRedisLock.Lock() defer synMysqlToRedisLock.Lock() var tempObj *model.Product if err := model.DB.Model(&model.Product{}).First(&tempObj, req.ID).Error; err != nil { controller.Error(c, err.Error()) return } b, err := json.Marshal(tempObj) if err != nil { controller.Error(c, err.Error()) return } v, err = redistab.RedisClient.Set(redistab.GetProductDetail(req.ID), string(b), 0).Result() fmt.Println("1---------", v, err) if err != nil { controller.Error(c, err.Error()) return } v, _ = redistab.RedisClient.Get(redistab.GetProductDetail(req.ID)).Result() } err = json.Unmarshal([]byte(v), &productObj) if err != nil { controller.Error(c, err.Error()) return } //增加统计,增加去重统计 该商品的DAU _, _ = redistab.RedisClient.PFAdd(redistab.GetProductDetailLogCount(req.ID)).Result() controller.Success(c, productObj) return } func getUuid() string{ id := uuid.NewV4() return id.String() }