栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

详解Go库存扣减如何实现的(多种方法)

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

详解Go库存扣减如何实现的(多种方法)

本文由golang教程栏目给大家介绍关于Go 库存扣减的几种实现方法,希望对需要的朋友有所帮助!

Go 库存扣减的几种实现方法

这里使用了 grpc、proto、gorm、zap、go-redis、go-redsync 等 package

Go Mutex 实现
var m sync.Mutexfunc (*InventoryServer) LockSell(ctx context.Context, req *proto.SellInfo) (*emptypb.Empty, error) {    tx := global.DB.Begin()    m.Lock()     for _, good := range req.GoodsInfo {        var i model.Inventory        if result := global.DB.Where(&model.Inventory{Goods: good.GoodsId}).First(&i);              result.RowsAffected == 0 {            tx.Rollback() // 回滚            return nil, status.Errorf(codes.InvalidArgument, "未找到此商品的库存信息。")        }        if i.Stocks < good.Num {            tx.Rollback()             return nil, status.Errorf(codes.ResourceExhausted, "此商品的库存不足")        }        i.Stocks -= good.Num        tx.Save(&i)    }    tx.Commit()    m.Unlock()    return &emptypb.Empty{}, nil}
MySQL 悲观锁实现
func (*InventoryServer) ForUpdateSell(ctx context.Context, req *proto.SellInfo) (*emptypb.Empty, error) {    tx := global.DB.Begin()    for _, good := range req.GoodsInfo {        var i model.Inventory        if result := tx.Clauses(clause.Locking{            Strength: "UPDATE",        }).Where(&model.Inventory{Goods: good.GoodsId}).First(&i);            result.RowsAffected == 0 {            tx.Rollback()            return nil, status.Errorf(codes.InvalidArgument, "未找到此商品的库存信息。")        }        if i.Stocks < good.Num {            tx.Rollback()            return nil, status.Errorf(codes.ResourceExhausted, "此商品的库存不足")        }        i.Stocks -= good.Num        tx.Save(&i)    }    tx.Commit()    return &emptypb.Empty{}, nil}
MySQL 乐观锁实现
func (*InventoryServer) VersionSell(ctx context.Context, req *proto.SellInfo) (*emptypb.Empty, error) {    tx := global.DB.Begin()    for _, good := range req.GoodsInfo {        var i model.Inventory        for { // 并发请求相同条件比较多,防止放弃掉一些请求            if result := global.DB.Where(&model.Inventory{Goods: good.GoodsId}).First(&i);                result.RowsAffected == 0 {                tx.Rollback()                return nil, status.Errorf(codes.InvalidArgument, "未找到此商品的库存信息.")            }            if i.Stocks < good.Num {                tx.Rollback() // 回滚                return nil, status.Errorf(codes.ResourceExhausted, "此商品的库存不足")            }            i.Stocks -= good.Num            version := i.Version + 1            if result := tx.Model(&model.Inventory{}).                Select("Stocks", "Version").                Where("goods = ? and version= ?", good.GoodsId, i.Version).                Updates(model.Inventory{Stocks: i.Stocks, Version: version});                result.RowsAffected == 0 {                                zap.S().Info("库存扣减失败!")            } else {                break            }        }    }    tx.Commit() // 提交    return &emptypb.Empty{}, nil}
Redis 分布式锁实现
func (*InventoryServer) RedisSell(ctx context.Context, req *proto.SellInfo) (*emptypb.Empty, error) {    // redis 分布式锁    pool := goredis.NewPool(global.Redis)    rs := redsync.New(pool)    tx := global.DB.Begin()    for _, good := range req.GoodsInfo {        mutex := rs.NewMutex(fmt.Sprintf("goods_%d", good.GoodsId))        if err := mutex.Lock(); err != nil {            return nil, status.Errorf(codes.Internal, "redis:分布式锁获取异常")        }        var i model.Inventory        if result := global.DB.Where(&model.Inventory{Goods: good.GoodsId}).First(&i); result.RowsAffected == 0 {            tx.Rollback()            return nil, status.Errorf(codes.InvalidArgument, "未找到此商品的库存信息")        }        if i.Stocks < good.Num {            tx.Rollback()            return nil, status.Errorf(codes.ResourceExhausted, "此商品的库存不足")        }        i.Stocks -= good.Num        tx.Save(&i)        if ok, err := mutex.Unlock(); !ok || err != nil {            return nil, status.Errorf(codes.Internal, "redis:分布式锁释放异常")        }    }    tx.Commit()    return &emptypb.Empty{}, nil}

测试

涉及到服务、数据库等环境,此测试为伪代码

func main() {  var w sync.WaitGroup  w.Add(20)  for i := 0; i < 20; i++ {      go TestForUpdateSell(&w) // 模拟并发请求  }  w.Wait()}func TestForUpdateSell(wg *sync.WaitGroup) {     defer wg.Done()  _, err := invClient.Sell(context.Background(), &proto.SellInfo{      GoodsInfo: []*proto.GoodsInvInfo{     {GoodsId: 16, Num: 1},  //{GoodsId: 16, Num: 10},      },  })  if err != nil {      panic(err) }  fmt.Println("库存扣减成功")}

以上就是详解Go库存扣减如何实现的(多种方法)的详细内容,更多请关注考高分网其它相关文章!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/793717.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号