Maison > développement back-end > Golang > le corps du texte

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

藏色散人
Libérer: 2022-01-18 16:07:27
avant
3133 Les gens l'ont consulté

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}
Copier après la connexion
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}
Copier après la connexion
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}
Copier après la connexion
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}
Copier après la connexion

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("库存扣减成功")}
Copier après la connexion

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!

Étiquettes associées:
go
source:learnku.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!