Maison >développement back-end >Golang >Explication détaillée de la façon dont la déduction d'inventaire est mise en œuvre dans Go (plusieurs méthodes)

Explication détaillée de la façon dont la déduction d'inventaire est mise en œuvre dans Go (plusieurs méthodes)

藏色散人
藏色散人avant
2022-01-18 16:07:273199parcourir

Cet article est rédigé par la rubrique tutoriel golang pour vous présenter plusieurs méthodes de mise en œuvre de la déduction d'inventaire Go. J'espère qu'il sera utile aux amis dans le besoin !

Plusieurs méthodes d'implémentation de la déduction d'inventaire Go

Grpc, proto, gorm, zap, go-redis, go-redsync et d'autres packages sont utilisés ici

Implémentation 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}
Verrou pessimiste MySQL Implémenter
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}
Implémentation du verrouillage optimiste 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}
Implémentation du verrouillage distribué 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}

Test

implique des services, des bases de données et d'autres environnements, ce test est un pseudo code

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("库存扣减成功")}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer