1
This commit is contained in:
parent
a76358a89e
commit
9a5da6bcad
2
go.mod
2
go.mod
@ -5,6 +5,8 @@ go 1.18
|
|||||||
require (
|
require (
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/go-redis/redis v6.15.9+incompatible
|
github.com/go-redis/redis v6.15.9+incompatible
|
||||||
|
github.com/gorilla/websocket v1.5.0
|
||||||
|
github.com/satori/go.uuid v1.2.0
|
||||||
gorm.io/driver/mysql v1.5.1
|
gorm.io/driver/mysql v1.5.1
|
||||||
gorm.io/gorm v1.25.3
|
gorm.io/gorm v1.25.3
|
||||||
)
|
)
|
||||||
|
4
go.sum
4
go.sum
@ -45,6 +45,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
@ -79,6 +81,8 @@ github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZ
|
|||||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||||
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
@ -6,8 +6,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-redis/redis"
|
"github.com/go-redis/redis"
|
||||||
|
"github.com/satori/go.uuid"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
"worktest/pkg/controller"
|
"worktest/pkg/controller"
|
||||||
"worktest/pkg/model"
|
"worktest/pkg/model"
|
||||||
"worktest/pkg/redistab"
|
"worktest/pkg/redistab"
|
||||||
@ -25,6 +28,8 @@ type DetailReq struct {
|
|||||||
|
|
||||||
var synMysqlToRedisLock sync.RWMutex
|
var synMysqlToRedisLock sync.RWMutex
|
||||||
|
|
||||||
|
var buych = make(chan int,1)
|
||||||
|
|
||||||
func MysqlList(c *gin.Context) {
|
func MysqlList(c *gin.Context) {
|
||||||
var req ListReq
|
var req ListReq
|
||||||
if err := c.ShouldBind(&req); err != nil {
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
@ -42,15 +47,13 @@ func MysqlList(c *gin.Context) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RedisBuy(c *gin.Context) {
|
func NormalMysqlBuy(c *gin.Context) {
|
||||||
var req DetailReq
|
var req DetailReq
|
||||||
if err := c.ShouldBind(&req); err != nil {
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
controller.Error(c, err.Error())
|
controller.Error(c, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var list []*model.Product
|
|
||||||
model.DB.Model(&model.Product{}).Find(&list)
|
|
||||||
|
|
||||||
err := model.DB.Transaction(func(tx *gorm.DB) error {
|
err := model.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
var obj *model.Product
|
var obj *model.Product
|
||||||
@ -72,8 +75,10 @@ func RedisBuy(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//扣除库存
|
//扣除库存
|
||||||
model.DB.Model(&model.Product{}).Where(&model.Product{ID: req.ID}).UpdateColumn("stock_size", gorm.Expr("stock_size - 1"))
|
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
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -83,9 +88,7 @@ func RedisBuy(c *gin.Context) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("2--------", redistab.RedisClient)
|
controller.Success(c, nil)
|
||||||
|
|
||||||
controller.Success(c, list)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -98,8 +101,290 @@ func MysqlBuy(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var list []*model.Product
|
|
||||||
model.DB.Model(&model.Product{}).Find(&list)
|
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 {
|
err := model.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
var obj *model.Product
|
var obj *model.Product
|
||||||
@ -134,24 +419,156 @@ func MysqlBuy(c *gin.Context) {
|
|||||||
|
|
||||||
fmt.Println("2--------", redistab.RedisClient)
|
fmt.Println("2--------", redistab.RedisClient)
|
||||||
|
|
||||||
controller.Success(c, list)
|
controller.Success(c, "购买成功")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RedisList(c *gin.Context) {
|
func RedisList(c *gin.Context) {
|
||||||
var req ListReq
|
var req ListReq
|
||||||
|
var productKeys []string
|
||||||
|
var productList []*model.Product
|
||||||
if err := c.ShouldBind(&req); err != nil {
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
controller.Error(c, err.Error())
|
controller.Error(c, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var list []*model.Product
|
//vals, err :=redistab.RedisClient.ZRange(redistab.GetProductIdZet(),0,-1).Result()
|
||||||
model.DB.Model(&model.Product{}).Find(&list)
|
//fmt.Println("1--------",vals,err)
|
||||||
fmt.Println("2--------", redistab.RedisClient)
|
|
||||||
|
//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)
|
||||||
|
|
||||||
controller.Success(c, list)
|
|
||||||
//统计人获取的次数
|
//统计人获取的次数
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -349,6 +766,67 @@ func RedisCountProduct(c *gin.Context) {
|
|||||||
return
|
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) {
|
func RedisDetailBitMapCount(c *gin.Context) {
|
||||||
var productObj *model.Product
|
var productObj *model.Product
|
||||||
var req DetailReq
|
var req DetailReq
|
||||||
@ -409,3 +887,9 @@ func RedisDetailBitMapCount(c *gin.Context) {
|
|||||||
controller.Success(c, productObj)
|
controller.Success(c, productObj)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getUuid() string{
|
||||||
|
id := uuid.NewV4()
|
||||||
|
return id.String()
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -4,7 +4,9 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-redis/redis"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
"worktest/pkg/model"
|
"worktest/pkg/model"
|
||||||
"worktest/pkg/redistab"
|
"worktest/pkg/redistab"
|
||||||
)
|
)
|
||||||
@ -152,6 +154,11 @@ func SynCache(c *gin.Context) {
|
|||||||
model.DB.Model(&model.Product{}).Find(&list)
|
model.DB.Model(&model.Product{}).Find(&list)
|
||||||
fmt.Println("2--------", redistab.RedisClient)
|
fmt.Println("2--------", redistab.RedisClient)
|
||||||
|
|
||||||
|
|
||||||
|
redistab.RedisClient.Del(redistab.GetProductBitMap())
|
||||||
|
redistab.RedisClient.Del(redistab.GetProductIdSet())
|
||||||
|
redistab.RedisClient.Del(redistab.GetProductIdZet())
|
||||||
|
|
||||||
for _, t := range list {
|
for _, t := range list {
|
||||||
v, err := redistab.RedisClient.Set(redistab.GetProductStockSize(t.ID), t.StockSize, 0).Result()
|
v, err := redistab.RedisClient.Set(redistab.GetProductStockSize(t.ID), t.StockSize, 0).Result()
|
||||||
fmt.Println("1---------", v, err)
|
fmt.Println("1---------", v, err)
|
||||||
@ -161,13 +168,49 @@ func SynCache(c *gin.Context) {
|
|||||||
fmt.Println("1---------", v, err)
|
fmt.Println("1---------", v, err)
|
||||||
|
|
||||||
//同步bitmap
|
//同步bitmap
|
||||||
redistab.RedisClient.Del(redistab.GetProductBitMap(), string(temp))
|
|
||||||
b, err := redistab.RedisClient.SetBit(redistab.GetProductBitMap(), int64(t.ID), 1).Result()
|
b, err := redistab.RedisClient.SetBit(redistab.GetProductBitMap(), int64(t.ID), 1).Result()
|
||||||
fmt.Println("1---------", b, err)
|
fmt.Println("1---------", b, err)
|
||||||
|
|
||||||
|
//id同步到set
|
||||||
|
redistab.RedisClient.SAdd(redistab.GetProductIdSet(),t.ID)
|
||||||
|
|
||||||
|
//id同步到zset
|
||||||
|
redistab.RedisClient.ZAdd(redistab.GetProductIdZet(),redis.Z{Score: float64(t.ID), Member: t.ID})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//同步列表
|
||||||
|
|
||||||
Success(c, list)
|
Success(c, list)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PublishMsg(c *gin.Context) {
|
||||||
|
|
||||||
|
for i := 0 ; i<=10 ; i++ {
|
||||||
|
msg := fmt.Sprintf("消息标号:%d号",i)
|
||||||
|
_= redistab.RedisClient.Publish(redistab.GetChannelKey(),msg) // 订阅 mychannel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Success(c, nil)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func PublishMsgTime(c *gin.Context) {
|
||||||
|
|
||||||
|
for i := 0 ; i<=10 ; i++ {
|
||||||
|
time.Sleep(100*time.Microsecond)
|
||||||
|
msg := fmt.Sprintf("消息标号:%d号",i)
|
||||||
|
_= redistab.RedisClient.Publish(redistab.GetChannelKey(),msg) // 订阅 mychannel
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Success(c, nil)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -15,6 +15,6 @@ type Product struct {
|
|||||||
// ProductOrder
|
// ProductOrder
|
||||||
type ProductOrder struct {
|
type ProductOrder struct {
|
||||||
ID uint `gorm:"primarykey"`
|
ID uint `gorm:"primarykey"`
|
||||||
ProductID uint `gorm:"column:ProductID" json:"ProductID"`
|
ProductID uint `gorm:"column:product_id" json:"productID"`
|
||||||
UserId uint `gorm:"column:UserID" json:"UserID"`
|
UserId uint `gorm:"column:user_id" json:"userID"`
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ var RedisClient *redis.Client
|
|||||||
func init() {
|
func init() {
|
||||||
RedisClient = redis.NewClient(&redis.Options{
|
RedisClient = redis.NewClient(&redis.Options{
|
||||||
Addr: "127.0.0.1:6379",
|
Addr: "127.0.0.1:6379",
|
||||||
Password: "",
|
Password: "123456",
|
||||||
PoolSize: 20,
|
PoolSize: 20,
|
||||||
DB: 1,
|
DB: 1,
|
||||||
})
|
})
|
||||||
|
@ -25,6 +25,26 @@ func GetProductBitMap() string {
|
|||||||
return fmt.Sprintf("product:bitmap")
|
return fmt.Sprintf("product:bitmap")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetProductIdSet() string {
|
||||||
|
return fmt.Sprintf("product:id:set")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetProductIdZet() string {
|
||||||
|
return fmt.Sprintf("product:id:zset")
|
||||||
|
}
|
||||||
|
|
||||||
func GetProductDetailLogCount(productId uint) string {
|
func GetProductDetailLogCount(productId uint) string {
|
||||||
return fmt.Sprintf("product:log_count:%d", productId)
|
return fmt.Sprintf("product:log_count:%d", productId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//某个商品的锁
|
||||||
|
func GetProductLockRedisKey(productId uint) string {
|
||||||
|
return fmt.Sprintf("product:lock:%d", productId)
|
||||||
|
}
|
||||||
|
|
||||||
|
//某个商品的锁
|
||||||
|
func GetChannelKey() string {
|
||||||
|
return fmt.Sprintf("product:channel" )
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,14 +18,19 @@ func RegisterRoute(router *gin.Engine) {
|
|||||||
backend.POST("all/cache/remove", controller.RemoveAllCache)
|
backend.POST("all/cache/remove", controller.RemoveAllCache)
|
||||||
backend.POST("cache/remove", controller.RemoveCache)
|
backend.POST("cache/remove", controller.RemoveCache)
|
||||||
backend.POST("syn/cache", controller.SynCache)
|
backend.POST("syn/cache", controller.SynCache)
|
||||||
|
|
||||||
|
backend.POST("publish/msg", controller.PublishMsg)
|
||||||
|
backend.POST("publish/time/msg", controller.PublishMsgTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
//首页列表部分
|
||||||
backend := v1.Group("/front")
|
backend := v1.Group("/front")
|
||||||
backend.POST("mysql/list", front.MysqlList) //数据库连接
|
backend.POST("mysql/list", front.MysqlList) //数据库连接
|
||||||
backend.POST("redis/list", front.RedisList) //缓存连接 string/hash
|
backend.POST("redis/list", front.RedisList) //缓存连接 string/hash
|
||||||
backend.POST("redis/", controller.List) //缓存
|
backend.POST("rec/list", front.RecList) //推荐列表 list
|
||||||
backend.POST("getlist", controller.List) //mysql
|
//#backend.POST("change/rec/list", front.List) //推荐列表 list
|
||||||
|
//#backend.POST("getlist", front.List) //推荐去除已买连接 set/zset
|
||||||
|
|
||||||
// jemter 对比
|
// jemter 对比
|
||||||
backend.POST("mysql/detail", front.MysqlDetail) //数据库连接
|
backend.POST("mysql/detail", front.MysqlDetail) //数据库连接
|
||||||
@ -35,25 +40,20 @@ func RegisterRoute(router *gin.Engine) {
|
|||||||
backend.POST("redis/bitmapcount/detail", front.RedisDetailBitMapCount) //redis单商品详情 锁保护 bitmap缓存击穿保护 增加访问统计
|
backend.POST("redis/bitmapcount/detail", front.RedisDetailBitMapCount) //redis单商品详情 锁保护 bitmap缓存击穿保护 增加访问统计
|
||||||
|
|
||||||
//增加bitmap的统计等
|
//增加bitmap的统计等
|
||||||
backend.POST("redis/bitmapcount/productcount", front.RedisCountProduct) //redis单商品详情 锁保护 bitmap缓存击穿保护 增加访问统计
|
backend.POST("redis/bitmapcount/productcount", front.RedisCountProduct) //redis 增加bitmap的统计等
|
||||||
|
|
||||||
backend.POST("mysql/buy", front.MysqlBuy) //抢购 mysql事务
|
|
||||||
backend.POST("redis/tx/buy", front.RedisBuy) //redistab 事务抢购 watch unwatch mutile exec
|
|
||||||
backend.POST("redis/lock/buy", controller.List) //redistab 分布式锁抢购 setNx lua
|
|
||||||
backend.POST("gortout/buy", controller.List) //go语言锁抢购,协程模拟锁
|
|
||||||
backend.POST("getlist", controller.List) //go语言锁抢购
|
|
||||||
|
|
||||||
/*
|
//抢购 watch事务 锁 list(未演示)
|
||||||
|
backend.POST("mysql/buy", front.NormalMysqlBuy) //抢购 mysql事务
|
||||||
|
backend.POST("mysql/tx/buy", front.MysqlBuy) //抢购 mysql事务
|
||||||
|
backend.POST("redis/tx/buy", front.RedisTxBuy) //redistab 事务抢购 watch unwatch mutile exec
|
||||||
|
backend.POST("redis/lock/buy", front.RedisLockBuy) //redistab 分布式锁抢购 setNx lua
|
||||||
|
backend.POST("channelLock/buy", front.GoroutineBuy ) //go语言锁抢购,协程模拟锁 分布部署则失效
|
||||||
|
//backend.POST("getlist", controller.List) //go语言锁抢购 略
|
||||||
|
|
||||||
backend.POST("getlist", controller.List) //推荐列表 list
|
//广播
|
||||||
backend.POST("getlist", controller.List) //推荐去除已买连接 set/zset
|
backend.GET("channel/receive", front.RedisRecWebsocket) //websocket redistab 广播 receive
|
||||||
|
backend.GET("redis/receive", front.RedisWebsocket) //websocket redistab 广播 chain
|
||||||
//jemter对比
|
|
||||||
backend.POST("getlist", controller.List) //websocket redistab 广播 receive
|
|
||||||
backend.POST("getlist", controller.List) //websocket redistab 广播 chain
|
|
||||||
backend.POST("getlist", controller.List) //websocket go通信 协程通信
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user