You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

896 lines
19 KiB
Go

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()
}