目录
并发请求秒杀正常,没有出现超卖情况
package main
import (
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis"
"math/rand"
"net/http"
"time"
"visual/common"
)
const (
KEY = "SecKill"
UserKey = "SecKill_User"
)
var (
GoodTotal int
)
var StartTime string = "2022-01-19 04:37:00"
var SecKillStart int = 0
func Redis() *redis.Client {
client := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379", Password: "", DB: 0})
_, err := client.Ping().Result()
if err != nil {
fmt.Println("Redis NewClient Error")
}
return client
}
func HttpClient() {
router := gin.Default()
router.GET("sec/kill", SecKill)
router.GET("sec/test", Y)
err := router.Run(":9999")
if err != nil {
fmt.Println("Router start failed")
}
}
func GetUserId() int {
return rand.Int()
}
func Y(c *gin.Context) {
Redis().Set("tttt", 222, 0)
c.AbortWithStatusJSON(http.StatusOK, gin.H{"Code": "201", "message": "YYYY"})
}
func SecKill(c *gin.Context) {
l,_ := time.LoadLocation("Asia/Shanghai")
startTime, _ := time.ParseInLocation(common.DateFormat, StartTime, l)
//到了秒杀时间,并且有货
if SecKillStart != 1 && time.Now().After(startTime) {
SecKillStart = 1
}
//已购数量
num, err := Redis().Get(KEY).Int()
if err != nil && err != redis.Nil {
c.AbortWithStatusJSON(http.StatusOK, gin.H{"Code": "201", "message": "秒杀失败"})
return
}
if num >= GoodTotal {
c.AbortWithStatusJSON(http.StatusOK, gin.H{"Code": "200", "message": "秒杀失败-抢光了1"})
return
}
userId := GetUserId()
//监视key,如果key被抢占改动,则事务打断
Txf := func(tx *redis.Tx) error {
num, err := tx.Get(KEY).Int()
if err != nil && err != redis.Nil {
return err
}
if num >= GoodTotal {
return errors.New("秒杀失败-抢光了2")
}
num++
_, err = tx.Pipelined(func(p redis.Pipeliner) error {
p.Set(KEY, num, 0)
p.RPush(UserKey, userId)
return nil
})
return err
}
if SecKillStart > 0 {
err = Redis().Watch(Txf, KEY)
if err != nil {
fmt.Println("Redis 监控失败")
c.AbortWithStatusJSON(http.StatusOK, gin.H{"Code": "203", "message": "秒杀失败2"})
return
}
} else {
c.AbortWithStatusJSON(http.StatusOK, gin.H{"Code": "200", "message": "秒杀失败尚未开始"})
return
}
c.AbortWithStatusJSON(http.StatusOK, gin.H{"Code": "200", "message": "秒杀成功"})
return
}
func main() {
GoodTotal = 2
HttpClient()
}