3-测试go-redis+redsync实现分布式锁
1.go-redis+redsync实现分布式锁测试效果
a.测试页面
mysql
复制代码
测试页面:--这里使用 Postman 来做测试
http://127.0.0.1:8000/goods/lockbuyone
b.测试效果
go
复制代码
查看终端: -- 使用ab软件并发100个请求
请求:$ ab -c 100 -n 100 http://127.0.0.1:8000/goods/lockbuyone
1.模拟现实同时下单
2.库存不能为负数
3.每次减库存时要上锁,减好库存要解锁
ab -c 10 -n 10 http://127.0.0.1:8000/goods/lockbuyone
2.go-redis+redsync实现分布式锁代码实现
a.路由的路径映射
go
复制代码
/routers/routers.go
操作:
1.测试需要一个路由
//商品路由部分
goods_r := r.Group("/goods/")
{
//上锁-减库存-解锁
goods_c := controllers.NewGoodsController()
goods_r.GET("/lockbuyone", goods_c.LockBuyOne)
}
b.控制器实现逻辑
go
复制代码
/controller/goodsController.go
操作:
1.首先知道两个参数:商品号和减几个
2.将以上两个参数带入相应的服务函数
package controllers
import (
"gitee.com/wao520/obtain_data/pkg/result"
"gitee.com/wao520/obtain_data/service"
"github.com/gin-gonic/gin"
)
type GoodsController struct{}
func NewGoodsController() *GoodsController {
return &GoodsController{}
}
// 购买一件商品,by lock
func (g *GoodsController) LockBuyOne(c *gin.Context) {
result := result.NewResult(c)
var goodsId int64 = 3
buyNum := 2
err := service.LockBuyOneGoods(goodsId, buyNum)
if err != nil {
result.ErrorCode(404, "数据查询错误")
} else {
result.Success("减库存成功")
}
}
c.在服务里上锁解锁
go
复制代码
/service/goods.go
操作:
1.根据商品号,制作一个与商品号相应的分布式锁
2.减库存前把锁锁上,其他相应需要等待
3.到mysql数据库减库存
4.减好库存,将锁解开,其他相应可以获得锁
package service
import (
"strconv"
"gitee.com/wao520/obtain_data/dao"
"gitee.com/wao520/obtain_data/global"
"github.com/go-redsync/redsync/v4"
"github.com/go-redsync/redsync/v4/redis/goredis/v8"
)
// 购买一件商品,by lock
func LockBuyOneGoods(goodsId int64, buyNum int) error {
//fmt.Println("begin LockBuyOneGoods")
pool := goredis.NewPool(global.RedisDb)
rs := redsync.New(pool)
mutexname := "goods_" + strconv.FormatInt(goodsId, 10)
mutex := rs.NewMutex(mutexname)
if err := mutex.Lock(); err != nil {
return err
}
errdecre := dao.DecreaseOneGoodsStock(goodsId, buyNum)
if ok, err := mutex.Unlock(); !ok || err != nil {
return err
}
if errdecre != nil {
return errdecre
}
return nil
}
d.数据库减库存
go
复制代码
/dao/goods.go
操作:
1.根据商品号,从mysql数据库获得库存
2.如果商品要买的数量大于库存,那么返回库存不足警告
3.如果库存充足,那么执行减库存操作
package dao
import (
"errors"
"fmt"
"gitee.com/wao520/obtain_data/global"
"gitee.com/wao520/obtain_data/model"
"gorm.io/gorm"
)
// decrease stock
func DecreaseOneGoodsStock(goodsId int64, buyNum int) error {
fmt.Println("DecreaseOneGoodsStock begin")
//查询商品信息
goodsOne := &model.Goods{}
err := global.DBLink.Where("goodsId=?", goodsId).First(&goodsOne).Error
//fmt.Println(goodsOne)
if err != nil {
return err
}
//得到库存
stock := goodsOne.Stock
fmt.Println(goodsOne.GoodsName, "当前库存:", stock)
//fmt.Println(stock)
if stock < buyNum || stock <= 0 {
return errors.New("库存不足")
}
//减库存 .Debug()
result := global.DBLink.Table("goods").Where("goodsId = ? ", goodsId).Update("stock", gorm.Expr("stock - ?", buyNum))
if result.Error != nil {
return result.Error
} else {
fmt.Println("成功减库存一次")
return nil
}
}
e.创建数据表模型
go
复制代码
/model/goods.go
操作:
1.可以使用模型获取数据库数据
package model
type Goods struct {
GoodsId int64 `gorm:"column:goodsId" json:"goodsid"` // 自增
GoodsName string `gorm:"column:goodsName" json:"goodsname"`
Subject string `gorm:"column:subject" json:"subject"`
Price string `gorm:"column:price" json:"price"`
Stock int `gorm:"column:stock" json:"stock"`
}
func (Goods) TableName() string {
return "goods"
}
f.数据库操作
mysql
复制代码
操作:
1.给数据库建表和增加测试数据
# mysql -uroot -p
mysql> use obtain_data;
CREATE TABLE `goods` (
`goodsId` int NOT NULL AUTO_INCREMENT COMMENT 'id',
`goodsName` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '商品名称',
`subject` varchar(200) NOT NULL DEFAULT '' COMMENT '标题',
`price` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT '价格',
`stock` int NOT NULL DEFAULT '0' COMMENT '库存数量',
PRIMARY KEY (`goodsId`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商品表';
INSERT INTO `goods` (`goodsId`, `goodsName`, `subject`, `price`, `stock`) VALUES
(1, '蜂蜜牛奶手工皂', '深入滋养,肌肤细腻嫩滑', '60.00', 5),
(2, '紫光筷子筒', '紫光智护,干爽防潮更健康', '169.00', 35),
(3, '野性mini便携式蓝牙音箱', '强悍机能,品味豪迈', '399.00', 88),
(4, '乐穿梭茶具', '茶具+茶叶精美端午礼盒', '188.00', 26);
3.获取开源项目
a.gin框架用go-redis+redsync实现分布式锁
b.本测试代码下载