修改秒杀
This commit is contained in:
144
kills/kill.go
144
kills/kill.go
@@ -7,40 +7,14 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
"toutoukan/init/redisInit"
|
||||
"toutoukan/model/usermodel/userOrder"
|
||||
"toutoukan/rocketmq/killmq/mqproducer"
|
||||
"toutoukan/utill/scripts"
|
||||
)
|
||||
|
||||
const (
|
||||
colorRed = "\033[31m" // 红色
|
||||
colorGreen = "\033[32m" // 绿色
|
||||
colorYellow = "\033[33m" // 黄色
|
||||
colorBlue = "\033[34m" // 蓝色
|
||||
colorReset = "\033[0m" // 重置颜色
|
||||
)
|
||||
|
||||
type Goods struct {
|
||||
GID uint `gorm:"column:gid"`
|
||||
Stock int `gorm:"column:stock"`
|
||||
StartTime time.Time `gorm:"column:start_time"`
|
||||
EndTime time.Time `gorm:"column:end_time"`
|
||||
}
|
||||
|
||||
// Order 订单模型,对应 orders_list 表
|
||||
type Order struct {
|
||||
OrderId string `gorm:"column:order_id"` // 关联商品ID
|
||||
TradeTime time.Time `gorm:"column:trade_time"`
|
||||
}
|
||||
|
||||
// 为模型指定数据库表名
|
||||
func (Goods) TableName() string {
|
||||
return "goods_list"
|
||||
}
|
||||
|
||||
func (Order) TableName() string {
|
||||
return "oders_list"
|
||||
}
|
||||
func GenerateOrderID() string {
|
||||
timestamp := time.Now().Format("20060102150405")
|
||||
|
||||
@@ -55,89 +29,49 @@ func GenerateOrderID() string {
|
||||
}
|
||||
|
||||
func Userkill(c *gin.Context) {
|
||||
var req userOrder.UserRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误", "detail": err.Error()})
|
||||
return
|
||||
}
|
||||
fmt.Printf("用户%d请求购买%s", req.UserID, req.Order)
|
||||
|
||||
result, err := redisInit.RedisClient.Eval(context.Background(), scripts.Luascript_forkill, []string{"stock:10000", "mayiming"}, 1, GenerateOrderID()).Int()
|
||||
OrderID := GenerateOrderID()
|
||||
|
||||
// 1. Redis扣减库存(不变)
|
||||
result, err := redisInit.RedisClient.Eval(context.Background(), scripts.Luascript_forkill, []string{req.Order, "mayiming"}, 1, OrderID).Int()
|
||||
if err != nil {
|
||||
log.Printf("Redis 脚本执行错误: %v", err)
|
||||
c.JSON(500, gin.H{"error": "库存操作失败", "detail": err.Error()})
|
||||
return
|
||||
}
|
||||
if result == 1 {
|
||||
c.JSON(200, gin.H{"result": "库存扣减成功"})
|
||||
} else {
|
||||
if result != 1 {
|
||||
c.JSON(200, gin.H{"result": "库存不足,扣减失败"})
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
// 2. 发送MQ消息(关键:发送失败需回滚Redis)
|
||||
msgSent := false
|
||||
defer func() {
|
||||
// 若消息未发送成功,回滚Redis库存
|
||||
if !msgSent {
|
||||
log.Printf("消息发送失败,回滚Redis库存,商品: %s,用户: %d", req.Order, req.UserID)
|
||||
// 回滚Redis:库存+1,同时移除可能的订单记录(根据Lua脚本逻辑调整)
|
||||
redisInit.RedisClient.Incr(context.Background(), req.Order)
|
||||
// 若Lua脚本中记录了订单ID(如存到set中),也需删除
|
||||
//redisInit.RedisClient.SRem(context.Background(), req.Order, OrderID)
|
||||
}
|
||||
}()
|
||||
|
||||
//func Userkill(c *gin.Context) {
|
||||
// // 直接使用全局初始化好的 UserDB 连接池
|
||||
// db := databaseInit.UserDB
|
||||
// if db == nil {
|
||||
// log.Printf("%sUserDB 未初始化,请先调用 InitUserDB()%s\n", colorRed, colorReset)
|
||||
// c.JSON(500, gin.H{"error": "系统数据库未初始化"})
|
||||
// return
|
||||
// }
|
||||
// fmt.Printf("%s用户请求处理完成%s\n", colorBlue, colorReset)
|
||||
//
|
||||
// // 定义要查询的商品ID
|
||||
// var targetGID uint = 1
|
||||
// var goods Goods
|
||||
//
|
||||
// tx := db.Begin()
|
||||
// if tx.Error != nil {
|
||||
// log.Printf("%s开启事务失败: %v%s\n", colorRed, tx.Error, colorReset)
|
||||
// c.JSON(500, gin.H{"body": "事务开启失败"})
|
||||
// return
|
||||
// }
|
||||
// result := tx.Set("gorm:query_option", "FOR UPDATE").Where("gid = ?", targetGID).First(&goods)
|
||||
// if result.Error != nil {
|
||||
// tx.Rollback() // 失败回滚事务
|
||||
// log.Printf("%s查询商品失败: %v%s\n", colorRed, result.Error, colorReset)
|
||||
// c.JSON(404, gin.H{"error": "商品不存在"})
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // 2. 检查库存是否充足
|
||||
// if goods.Stock <= 0 {
|
||||
// tx.Rollback()
|
||||
// log.Printf("%s商品库存不足%s\n", colorYellow, colorReset)
|
||||
// c.JSON(400, gin.H{"error": "商品库存不足"})
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // 3. 生成订单
|
||||
// userorder := Order{
|
||||
// OrderId: GenerateOrderID(),
|
||||
// TradeTime: time.Now(),
|
||||
// }
|
||||
// if err := tx.Create(&userorder).Error; err != nil {
|
||||
// tx.Rollback()
|
||||
// log.Printf("%s创建订单失败: %v%s\n", colorRed, err, colorReset)
|
||||
// c.JSON(500, gin.H{"error": "创建订单失败"})
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // 4. 扣减库存(库存-1)
|
||||
// if err := tx.Model(&Goods{}).Where("gid = ?", targetGID).Update("stock", goods.Stock-1).Error; err != nil {
|
||||
// tx.Rollback()
|
||||
// log.Printf("%s扣减库存失败: %v%s\n", colorRed, err, colorReset)
|
||||
// c.JSON(500, gin.H{"error": "库存更新失败"})
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // 5. 提交事务
|
||||
// if err := tx.Commit().Error; err != nil {
|
||||
// tx.Rollback()
|
||||
// log.Printf("%s提交事务失败: %v%s\n", colorRed, err, colorReset)
|
||||
// c.JSON(500, gin.H{"error": "系统错误"})
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// log.Printf("%s订单创建成功,订单ID: %s,剩余库存: %d%s\n", colorGreen, userorder.OrderId, goods.Stock-1, colorReset)
|
||||
// c.JSON(200, gin.H{
|
||||
// "message": "下单成功",
|
||||
// "order_id": userorder.OrderId,
|
||||
// "stock": goods.Stock - 1,
|
||||
// })
|
||||
//}
|
||||
// 发送消息(同步发送,确保拿到发送结果)
|
||||
sendErr := mqproducer.SendNormalMessage(OrderID, req.Order, req.UserID)
|
||||
if sendErr != nil {
|
||||
log.Printf("MQ消息发送失败: %v", sendErr)
|
||||
c.JSON(500, gin.H{"error": "消息发送失败", "detail": sendErr.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// 消息发送成功,标记为已发送(避免defer回滚)
|
||||
msgSent = true
|
||||
c.JSON(200, gin.H{"result": "库存扣减成功"})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user