首页 > 数据库 >3-测试go-redis+redsync实现分布式锁 --开源项目obtain_data测试

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

时间:2024-11-22 20:44:03浏览次数:3  
标签:goods err redis obtain goodsId 库存 测试 go stock

3-测试go-redis+redsync实现分布式锁

1.go-redis+redsync实现分布式锁测试效果

a.测试页面

测试页面:--这里使用 Postman 来做测试
http://127.0.0.1:8000/goods/lockbuyone

在这里插入图片描述

b.测试效果

查看终端:	-- 使用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.路由的路径映射

/routers/routers.go
操作:
1.测试需要一个路由

	//商品路由部分
	goods_r := r.Group("/goods/")
	{
		//上锁-减库存-解锁
		goods_c := controllers.NewGoodsController()
		goods_r.GET("/lockbuyone", goods_c.LockBuyOne)
	}

在这里插入图片描述

b.控制器实现逻辑

/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.在服务里上锁解锁

/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.数据库减库存

/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.创建数据表模型

/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.数据库操作

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

标签:goods,err,redis,obtain,goodsId,库存,测试,go,stock
From: https://blog.csdn.net/weixin_42478311/article/details/143962851

相关文章

  • 超强的渗透测试常用软件和命令分享(含代理扫描爬虫注入等),网络安全零基础入门到精通教程
    文章目录漏洞扫描xray设计理念简易架构来源处理漏洞检测结果输出代理模式生成ca证书安装ca证书启动代理配置代理开始扫描爬虫模式启动爬虫基础爬虫高级爬虫登录后的网站扫描服务扫描HTTP配置漏洞扫描用的代理多代理配置限制发包速度软件获取xrayRad正版授权Acuneti......
  • #渗透测试#SRC漏洞挖掘#网络运维# 黑客脚本编写07之for循环判断与while循环
    免责声明本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章阅读。                            ......
  • Redis的特性&&ubuntu进行安装
    文章目录1.六大特性1.1内存存储数据1.2可编程1.3可扩展1.4持久化1.5集群1.6高可用1.7速度快2.具体应用场景(了解)3.Ubuntu安装Redis3.1安装指令3.2查看状态3.3查找配置文件3.4修改文件内容3.5重启服务器生效3.6安装客户端并进行检查4.Redis客户端介绍1.六大特性redis......
  • EMC电磁兼容设计与测试案例分析(第3版)(11.22)
    EMC电磁兼容设计与测试案例分析(第3版)(11.22)EMC电磁兼容设计与测试案例:1、EMC共模电流不入地2、金属外壳可以更好接地、屏蔽线缆:单端/双端接地是否存在连接层导致双端失效3、电感频增而增;电容频增而减;串感、并荣;有概率发生谐振(点),应避开emc测试点4、浪涌与过压:低频、干扰......
  • [微服务] 为 gRPC 服务添加 JWT 认证,使用 Apifox 客户端进行测试
    gRPC测试客户端Apifox=Postman+Swagger+Mock+JMeterhttps://apifox.com/ 为何使用gRPC?相较于REST使用gRPC服务具有以下优势:性能方面高效的通信协议gRPC基于HTTP/2协议,而RESTfulAPI通常基于HTTP/1.1。HTTP/2支持多路复用,能在一个TCP连接上同时......
  • Linux-Cent7.9 redis路径查找 | 删除redis所有缓存
    查看redis端口命令[root@VM-20-17-centosetc]#ps-ef|grepredisredis125710Nov20?00:02:06/usr/bin/redis-server0.0.0.0:6379root63406653015:27pts/000:00:00grep--color=autoredis发现redis-server对应端口为1257查看r......
  • 开放性实验——网络安全渗透测试
    网络安全渗透测试实验报告一、实验环境操作机:虚拟机kalilinux目标主机:虚拟机win7:(192.168.1.116)KaliLinux和win7均采用桥接模式二、实验工具KaliLinux上的metasploit扫描器nessusNmap三、攻击目标利用ms17-010漏洞查看目的主机的用户并添加一个用户为管理员。......
  • Go语言实践测试
    单元测试规则所有测试文件以_test.go结尾所有的测试方法以funcTestXxx(*testing.T),如果这个命名和实现正确在文件会有个可以运行的标志初始化逻辑放到TestMain中TestMain结构大致如下funcTestMain(m*testing.M){ //测试前:数据装载、配置初始化等前置工作 code:=m......
  • OpenAI 是怎么“压力测试”大型语言模型的?
    OpenAI再次稍微揭开了它的安全测试流程的面纱。上个月,他们分享了一项调查的结果,这项调查研究了ChatGPT在根据用户名字生成性别或种族偏见的几率。现在,他们又发布了两篇论文,详细描述了如何对大型语言模型进行“压力测试”(也叫红队测试),目的是找出可能有害或者其他不希望出现的行......
  • [EMC] 常规emc测试项目有哪些
    EMC(ElectroMagneticCompatibility)电磁兼容,是指设备或系统在其电磁环境中符合要求运行并不对其环境中的任何设备产生无法忍受的电磁干扰的能力。因此,EMC包括两个方面的要求:一方面是指设备在正常运行过程中对所在环境产生的电磁干扰不能超过一定的限值;另一方面是指设备对所在环......