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

相关推荐
凡人的AI工具箱1 小时前
40分钟学 Go 语言高并发:【实战】并发安全的配置管理器(功能扩展)
开发语言·后端·安全·架构·golang
Achou.Wang1 小时前
Redis过期时间和SORT命令的高级用法
数据库·redis·bootstrap
XMYX-02 小时前
Redis 在实际业务中的高效应用
redis
sx_17063 小时前
Spark面试题
大数据·分布式·spark
zybsjn4 小时前
MongoDB 和 Redis 是两种不同类型的数据库比较
数据库·redis·mongodb
wclass-zhengge4 小时前
02微服务系统与设计(D1_走出微服务误区:避免从单体到分布式单体)
分布式·微服务·架构
ZOMI酱5 小时前
【AI系统】分布式通信与 NVLink
人工智能·分布式
熬了夜的程序员6 小时前
使用Go语言实现线程安全的Map
安全·golang
克鲁德战士6 小时前
【Java并发编程的艺术3】Java内存模型(下)
java·开发语言·redis