站長資訊網
        最全最豐富的資訊網站

        詳解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("庫存扣減成功")}

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 少妇人妻偷人精品视频| 亚洲精品乱码久久久久66| 精品福利一区二区三区免费视频| 久久久无码精品亚洲日韩蜜臀浪潮| 久久久免费精品re6| 99久久夜色精品国产网站| 亚洲一区无码精品色| 国产成人精品免费视频大全| 国产精品无码a∨精品| 日本精品一区二区三区在线视频一 | 国产精品视频色视频| 久久综合精品国产二区无码| 亚洲第一永久AV网站久久精品男人的天堂AV| 北岛玲日韩精品一区二区三区| 欧洲成人午夜精品无码区久久| 久久久久无码精品国产不卡| 欧美精品播放| 精品久久久久久久久久中文字幕| 亚洲国产精品久久66| 久久精品国产亚洲av水果派| 国产亚洲精品AA片在线观看不加载| 国产精品gz久久久| 国产精品久久一区二区三区| 日韩精品无码AV成人观看| 欧美精品一区二区三区免费观看| 国产午夜精品久久久久九九电影| 日韩精品www| 国产产无码乱码精品久久鸭| 亚洲精品无码鲁网中文电影| 一色屋精品视频在线观看| 真实国产精品vr专区| 国产精品一区二区av| 四虎国产精品免费久久| 69堂午夜精品视频在线| 8x福利精品第一导航| 久久精品无码专区免费青青 | 国产精品久久久福利| 日韩精品专区在线影院重磅| 亚洲欧美精品SUV| 日韩精品无码AV成人观看| 日产精品久久久一区二区|