日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

用戶下單流程

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

用戶下單簡要過程

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

我們可以看到,下單是發生在結算之后,下單之后,會生成唯一的訂單號,接下來,客戶端需要用這個訂單號去完成支付。

那接下來先看看,為什么發生重復下單?

為什么會重復下單

為什么會重復下單,對于訂單服務而言,就是接到了多個下單的請求,原因可能有很多,最常見的是這兩種:

  • 用戶重復提交
  • 網絡原因導致的超時重試

重復下單原因

如何防止重復下單

防止用戶提交,最常規的做法,就是客戶端點擊下單之后,在收到服務端響應之前,按鈕置灰。

當然,防止重復下單,肯定不能只依靠客戶端,可能會因為一些網絡的抖動,導致仍然有重復的請求到達服務端,所以還是要在服務端做防重/冪等的處理。

PS:這里額外插入一點我對防重和冪等的理解:防重指的是防止重復提交,冪等指的是多次請求如一次,簡單說,就是防重可以給對重復請求拋異常,冪等是對重復的請求響應第一次的結果,在我們討論的這個場景里,冪等就是響應唯一的訂單號。

防重和冪等

防重第一步,需要識別請求是否重復,這一步,需要客戶端配合實現。

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

所以,需要客戶端在請求下單接口的時候,需要生成一個唯一的請求號:requestId,服務端拿這個請求號,判斷是否重復請求。

那么,接下來,壓力就給到服務端了,看看服務端怎么實現防重/冪等吧!

利用數據庫實現冪等

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

唯一請求字段

這樣一來,如果是重復的請求,在落庫的時候就會報錯,為了保證冪等性,我們可以catch住這個異常,根據requestId獲取訂單號,然后向客戶端響應訂單號。

大概的代碼如下:

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

當然,這里不太好的地方是,拿異常來做業務判斷。

利用redis防重

另外一個辦法,就是下單請求的時候要加鎖了,通常我們的服務都是集群部署,所以一般都是用Redis實現分布式鎖。

大概的邏輯:

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

redis防重邏輯

大概的代碼如下:

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

這里再說明一下:

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

因為下單里面其實還有一些其它的業務流程,比如鎖庫存、清優惠券……而此時,獲取到鎖的請求的下單流程還沒有結束,下單的結果還獲取不到,沒法完成響應,也就沒辦法做冪等。

客戶端,也可以根據響應的狀態碼,進行特殊處理,比如這個異常先不提示,但是允許用戶再次點擊下單按鈕,來提升用戶的體驗。

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

作者:三分惡

分享到:
標簽:下單 重復
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定