Penjelasan terperinci tentang cara potongan inventori dilaksanakan dalam Go (pelbagai kaedah)

藏色散人
Lepaskan: 2022-01-18 16:07:27
ke hadapan
3155 orang telah melayarinya

Artikel ini diperkenalkan oleh ruangan tutorial golang untuk memperkenalkan beberapa kaedah pelaksanaan potongan inventori Go. Semoga ia dapat membantu rakan-rakan yang memerlukan.

Beberapa kaedah pelaksanaan potongan inventori Go

Grpc, proto, gorm, zap, go-redis, go-redsync dan pakej lain digunakan di sini

Pelaksanaan 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}
Salin selepas log masuk
Pelaksanaan kunci pesimis 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}
Salin selepas log masuk
Pelaksanaan kunci optimistik 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}
Salin selepas log masuk
Pelaksanaan kunci diedarkan 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}
Salin selepas log masuk

Pengujian

Melibatkan perkhidmatan dan persekitaran pangkalan data, ini ujian ialah kod pseudo

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

Atas ialah kandungan terperinci Penjelasan terperinci tentang cara potongan inventori dilaksanakan dalam Go (pelbagai kaedah). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
go
sumber:learnku.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan