新聞中心
這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
詳解Go庫(kù)存扣減如何實(shí)現(xiàn)的(多種方法)
本文由golang教程欄目給大家介紹關(guān)于Go 庫(kù)存扣減的幾種實(shí)現(xiàn)方法,希望對(duì)需要的朋友有所幫助!

成都創(chuàng)新互聯(lián)是一家專注于網(wǎng)站建設(shè)、成都做網(wǎng)站與策劃設(shè)計(jì),兩當(dāng)網(wǎng)站建設(shè)哪家好?成都創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)十年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:兩當(dāng)?shù)鹊貐^(qū)。兩當(dāng)做網(wǎng)站價(jià)格咨詢:18982081108
Go 庫(kù)存扣減的幾種實(shí)現(xiàn)方法
Go Mutex 實(shí)現(xiàn)
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, "未找到此商品的庫(kù)存信息。")
}
if i.Stocks < good.Num {
tx.Rollback()
return nil, status.Errorf(codes.ResourceExhausted, "此商品的庫(kù)存不足")
}
i.Stocks -= good.Num
tx.Save(&i)
}
tx.Commit()
m.Unlock()
return &emptypb.Empty{}, nil}
MySQL 悲觀鎖實(shí)現(xiàn)
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, "未找到此商品的庫(kù)存信息。")
}
if i.Stocks < good.Num {
tx.Rollback()
return nil, status.Errorf(codes.ResourceExhausted, "此商品的庫(kù)存不足")
}
i.Stocks -= good.Num
tx.Save(&i)
}
tx.Commit()
return &emptypb.Empty{}, nil}
MySQL 樂觀鎖實(shí)現(xiàn)
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 { // 并發(fā)請(qǐng)求相同條件比較多,防止放棄掉一些請(qǐng)求
if result := global.DB.Where(&model.Inventory{Goods: good.GoodsId}).First(&i);
result.RowsAffected == 0 {
tx.Rollback()
return nil, status.Errorf(codes.InvalidArgument, "未找到此商品的庫(kù)存信息.")
}
if i.Stocks < good.Num {
tx.Rollback() // 回滾
return nil, status.Errorf(codes.ResourceExhausted, "此商品的庫(kù)存不足")
}
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("庫(kù)存扣減失敗!")
} else {
break
}
}
}
tx.Commit() // 提交
return &emptypb.Empty{}, nil}
Redis 分布式鎖實(shí)現(xiàn)
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, "未找到此商品的庫(kù)存信息")
}
if i.Stocks < good.Num {
tx.Rollback()
return nil, status.Errorf(codes.ResourceExhausted, "此商品的庫(kù)存不足")
}
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}
測(cè)試
func main() {
var w sync.WaitGroup
w.Add(20)
for i := 0; i < 20; i++ {
go TestForUpdateSell(&w) // 模擬并發(fā)請(qǐng)求
}
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("庫(kù)存扣減成功")} 網(wǎng)頁(yè)名稱:詳解Go庫(kù)存扣減如何實(shí)現(xiàn)的(多種方法)
當(dāng)前路徑:http://fisionsoft.com.cn/article/dpcpjpd.html


咨詢
建站咨詢
