亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

用戶下單流程

我們從用戶瀏覽商品開始,看看用戶下單的簡要過程:

用戶下單簡要過程

  • 瀏覽商品:用戶查看商品詳情
  • 加購/結(jié)算:用戶可以選擇直接購買商品,也可以先加入購物車,用戶購買的這一步就是結(jié)算
  • 確認(rèn)下單:結(jié)算完成,就進(jìn)入了下單頁面,提交訂單,這一步就會(huì)生成一個(gè)訂單,然后進(jìn)入付款頁面

我們可以看到,下單是發(fā)生在結(jié)算之后,下單之后,會(huì)生成唯一的訂單號(hào),接下來,客戶端需要用這個(gè)訂單號(hào)去完成支付。

那接下來先看看,為什么發(fā)生重復(fù)下單?

為什么會(huì)重復(fù)下單

為什么會(huì)重復(fù)下單,對(duì)于訂單服務(wù)而言,就是接到了多個(gè)下單的請求,原因可能有很多,最常見的是這兩種:

  • 用戶重復(fù)提交
  • 網(wǎng)絡(luò)原因?qū)е碌某瑫r(shí)重試

重復(fù)下單原因

如何防止重復(fù)下單

防止用戶提交,最常規(guī)的做法,就是客戶端點(diǎn)擊下單之后,在收到服務(wù)端響應(yīng)之前,按鈕置灰。

當(dāng)然,防止重復(fù)下單,肯定不能只依靠客戶端,可能會(huì)因?yàn)橐恍┚W(wǎng)絡(luò)的抖動(dòng),導(dǎo)致仍然有重復(fù)的請求到達(dá)服務(wù)端,所以還是要在服務(wù)端做防重/冪等的處理。

PS:這里額外插入一點(diǎn)我對(duì)防重和冪等的理解:防重指的是防止重復(fù)提交,冪等指的是多次請求如一次,簡單說,就是防重可以給對(duì)重復(fù)請求拋異常,冪等是對(duì)重復(fù)的請求響應(yīng)第一次的結(jié)果,在我們討論的這個(gè)場景里,冪等就是響應(yīng)唯一的訂單號(hào)。

防重和冪等

防重第一步,需要識(shí)別請求是否重復(fù),這一步,需要客戶端配合實(shí)現(xiàn)。

為什么呢?大家想一下,下單的時(shí)候,服務(wù)端怎么去判斷這個(gè)下單請求是否唯一呢?金額?商品?優(yōu)惠券?……萬一用戶就是喜歡,又下了一個(gè)一模一樣的單呢?

所以,需要客戶端在請求下單接口的時(shí)候,需要生成一個(gè)唯一的請求號(hào):requestId,服務(wù)端拿這個(gè)請求號(hào),判斷是否重復(fù)請求。

那么,接下來,壓力就給到服務(wù)端了,看看服務(wù)端怎么實(shí)現(xiàn)防重/冪等吧!

利用數(shù)據(jù)庫實(shí)現(xiàn)冪等

可以在訂單表t_order里添加一個(gè)字段:requestId,添加唯一索引:

唯一請求字段

這樣一來,如果是重復(fù)的請求,在落庫的時(shí)候就會(huì)報(bào)錯(cuò),為了保證冪等性,我們可以catch住這個(gè)異常,根據(jù)requestId獲取訂單號(hào),然后向客戶端響應(yīng)訂單號(hào)。

大概的代碼如下:

PlaceOrderResVO placeOrder(PlaceOrderReqVO reqVO) {
  try {
    //下單業(yè)務(wù)邏輯
    ……
    //生成訂單號(hào)
    String oid=generateOid();
    ……
    //訂單落庫
    Order order = orderMApper.saveOrder(orderDO); 
    //響應(yīng)訂單
    resVO.setOid(order.getOid());
    return resVO;
  } catch(UniqueKeyViolationException e) {
    // 發(fā)生了重復(fù)異常
    // 根據(jù)請求號(hào)獲取訂單
    Order order = getOrderByRequestId(reqVO.getRequestId());
    resVO.setOid(order.getOid());
    return resVO;
  } catch (Exception e) {
  }
}

當(dāng)然,這里不太好的地方是,拿異常來做業(yè)務(wù)判斷。

利用redis防重

另外一個(gè)辦法,就是下單請求的時(shí)候要加鎖了,通常我們的服務(wù)都是集群部署,所以一般都是用Redis實(shí)現(xiàn)分布式鎖。

大概的邏輯:

  • 就是以requestId為維度,進(jìn)行加鎖,如果獲取鎖失敗,就拋一個(gè)自定義的重復(fù)下單異常。
  • 如果獲取到鎖,先check一下,是否已經(jīng)下單,為了提高性能,下單完成后,也把下單的結(jié)果放在Redis緩存里。

redis防重邏輯

大概的代碼如下:

    public PlaceOrderResVO placeOrder(PlaceOrderReqVO reqVO) {
        //加鎖
        RLock orderLock = redissonClient.getLock(RedisConstant.PLACE_ORDER_LOCK_KEY + reqVO.getRequestId());
        //獲取鎖失敗,拋出重復(fù)下單異常
        if(orderLock.isExistes){
          throw new OrderRepeatException();
        }
        // 加鎖
        orderLock.lock();
        try {
            //檢查是否已經(jīng)下單
            RBucket<PlaceOrderResVO> orderCache = redissonClient.getBucket(RedisConstant.PLACE_ORDER_LOCK_KEY+reqVO.getRequestId());
            if(orderCache.isExistes){
                return orderCache.get();
            }
            //下單業(yè)務(wù)邏輯
            ……
            //落庫
            //訂單落庫
            Order order = orderMapper.saveOrder(orderDO); 
            ……
            //緩存結(jié)果
            orderCache.put(resVO);
            return resVO;
        } 
        } catch (Exception e) {
            //……
        } finally {
            orderLock.unlock();
        }
        return resVO;
    }

這里再說明一下:

  • 為什么獲取不到鎖的時(shí)候要拋異常呢?

因?yàn)橄聠卫锩嫫鋵?shí)還有一些其它的業(yè)務(wù)流程,比如鎖庫存、清優(yōu)惠券……而此時(shí),獲取到鎖的請求的下單流程還沒有結(jié)束,下單的結(jié)果還獲取不到,沒法完成響應(yīng),也就沒辦法做冪等。

客戶端,也可以根據(jù)響應(yīng)的狀態(tài)碼,進(jìn)行特殊處理,比如這個(gè)異常先不提示,但是允許用戶再次點(diǎn)擊下單按鈕,來提升用戶的體驗(yàn)。

原文鏈接:
https://mp.weixin.qq.com/s/Dc_4taB6Boojdw_0mngroQ

作者:三分惡

分享到:
標(biāo)簽:下單 重復(fù)
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評(píng)定2018-06-03

通用課目體育訓(xùn)練成績評(píng)定