当前位置: 首页 > article >正文

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

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


http://www.kler.cn/a/406861.html

相关文章:

  • 客户流失分析综述
  • Unity图形学之CubeMap立方体贴图
  • Kafka-Consumer理论知识
  • MATLAB GUI设计(基础)
  • 常用Adb 命令
  • Android opencv使用Core.hconcat 进行图像拼接
  • VRRP实现出口网关设备冗余备份
  • win10中使用ffmpeg和MediaMTX 推流rtsp视频
  • JAVA下载EXCEL,PDF文件之后无法打开,提示文件损坏
  • electron主进程和渲染进程之间的通信
  • 大数据学习18之Spark-SQL
  • STL关联式容器之multiset及multimap
  • Flutter:AnimatedSwitcher当子元素改变时,触发动画
  • Ansible使用简介和基础使用
  • 嵌入式 UI 开发的开源项目推荐
  • C#学习笔记——窗口停靠控件WeifenLuo.WinFormsUI.Docking使用-腾讯云开发者社区-腾讯云
  • vue3中父div设置display flex,2个子div重叠
  • 华为无线AC+AP组网实际应用小结
  • FreeIPCC:Ai智能呼叫中心是什么?
  • 【数据结构】归并排序 —— 递归及非递归解决归并排序
  • 基于自混合干涉测量系统的线展宽因子估计算法matlab仿真
  • Python Matplotlib 安装指南:使用 Miniconda 实现跨 Linux、macOS 和 Windows 平台安装
  • MAC C语言 Helloword
  • spring学习(四)
  • DevOps 之 CI/CD入门操作 (二)
  • k8s上面的Redis集群链接不上master的解决办法