3-测试go-redis+redsync实现分布式锁 --开源项目obtain_data测试

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.本测试代码下载

相关推荐
专注API从业者1 小时前
《Go 语言高并发爬虫开发:淘宝商品 API 实时采集与 ETL 数据处理管道》
开发语言·后端·爬虫·golang
青铜爱码士2 小时前
redis+lua+固定窗口实现分布式限流
redis·分布式·lua
王景程3 小时前
如何使用 Redis 缓存验证码
redis·缓存·mybatis
编程在手天下我有3 小时前
Redis 常见问题深度剖析与全方位解决方案指南
数据库·redis·缓存·性能优化·数据持久化·分布式系统
啊喜拔牙4 小时前
如何搭建spark yarn模式的集群
大数据·分布式·spark
听雨·眠4 小时前
关于kafka
分布式·kafka·消息队列
TE-茶叶蛋4 小时前
NestJS + Kafka 秒杀系统完整实践总结
分布式·kafka
类似不类似5 小时前
快速配置linux远程开发-go语言
开发语言·后端·golang
慧一居士5 小时前
Kafka批量消费部分处理成功时的手动提交方案
分布式·后端·kafka
搞不懂语言的程序员6 小时前
如何实现Kafka的Exactly-Once语义?
分布式·kafka·linq