一. 用go语言自带的锁。
下面代码为
抢购Api
。
//锁var mu sync.Mutex//抢购Apifunc (this *RushController) Purchase() {//商品IDgoods_id := int64(1)//加锁mu.Lock()//结束时解锁defer mu.Unlock()//ormo := orm.NewOrm()//读取商品信息m := models.Goods{Id: goods_id}err := o.Read(&m)if err != nil{code,_ := beego.AppConfig.Int(\"paramError\")this.ErrorJson(code, \"数据错误\")}//检查库存if m.Sku <= 0{code,_ := beego.AppConfig.Int(\"systemError\")this.ErrorJson(code, \"该商品已售罄\")}//更新库存m.Sku--_,err = o.Update(&m)//订单入库order := models.Order{UserId: 1,GoodsId: goods_id,CreateTime: time.Now().Unix(),}o.Insert(&order)//返回arr := make(map[string]interface{})this.SuccessJson(arr)}
二. 用go语言的channel。
下面代码为
处理订单进程
代码。
//订单channelvar chOrders chan models.Order = make(chan models.Order)// 抢购codeconst (buySuccess = iota // 抢购成功buyFail // 抢购失败)// 单线程死循环,专注处理数据更新func RunRush() {for {//接收订单order := <-chOrders//ormo := orm.NewOrm()//读取商品信息m := models.Goods{Id: order.GoodsId}o.Read(&m)if m.Sku <= 0 {//无库存,通知回调失败order.Callback <- buyFail}else{//有库存//更新库存m.Sku -= 1o.Update(&m)//订单入库o.Insert(&order)//通知回调成功order.Callback <- buySuccess}}}
下面代码为
抢购Api
。
//抢购Apifunc (this *RushController) Purchase() {//商品IDgoods_id := int64(1)//ormo := orm.NewOrm()//读取商品信息m := models.Goods{Id: goods_id}err := o.Read(&m)if err != nil{code,_ := beego.AppConfig.Int(\"paramError\")this.ErrorJson(code, \"数据错误\")}//检查库存if m.Sku <= 0{code,_ := beego.AppConfig.Int(\"systemError\")this.ErrorJson(code, \"该商品已售罄\")}// 构造一个回调的channelcallback := make(chan uint)//订单order := models.Order{UserId: 1,GoodsId: goods_id,CreateTime: time.Now().Unix(),Callback: callback,}// 把订单发送给channelchOrders <- order// 回调的channel等待处理结果code := <- callbackif code == buySuccess{//抢购成功arr := make(map[string]interface{})this.SuccessJson(arr)}else{//抢购失败code,_ := beego.AppConfig.Int(\"systemError\")this.ErrorJson(code, \"抢购失败\")}}
总结
优点:利用go语言自带的锁和channel,解决了并发抢购超卖的问题,实现快速,成本低。
缺点:阻塞是一个办法,但不是非常好的解决方案,它简单粗暴,没有队列的削峰填谷那般巧妙,单纯靠 加锁 用于小并发没事,高并发 加锁就是灾难,用户都在等待。。。
有什么高见欢迎大佬们在评论区指点。