首页后端开发其他后端知识Go库存扣减实现有多少方法,具体怎么做

Go库存扣减实现有多少方法,具体怎么做

时间2024-03-26 06:04:03发布访客分类其他后端知识浏览959
导读:今天就跟大家聊聊有关“Go库存扣减实现有多少方法,具体怎么做”的内容,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。 Go库存扣减的几种实现方法 这里使用了 grpc...
今天就跟大家聊聊有关“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库存扣减实现有多少方法,具体怎么做”的内容就介绍到这,感谢各位的阅读,相信大家对Go库存扣减实现有多少方法,具体怎么做已经有了进一步的了解。大家如果还想学习更多知识,欢迎关注网络,小编将为大家输出更多高质量的实用文章!

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


若转载请注明出处: Go库存扣减实现有多少方法,具体怎么做
本文地址: https://pptw.com/jishu/653307.html
ajax默认异步提交是怎样的,如何实现同步请求 ajax请求时post和get怎样选,有什么不同

游客 回复需填写必要信息