保證接口的冪等性(避免重複消費)

冪等:即相同條件下對同一個業務的操作,不管操作多少次,結果都是一樣的。比如存在如下場景:

  • 用戶提交文件,點擊確認之後,沒反應,就又點擊了幾次。在這種情況下,如果無法保證該接口的冪等性,那麼將會出現重複提交問題。下單也是一樣。

避免重複提交/下單的方案主要有以下幾種:

  • 悲觀鎖方案
  • 樂觀鎖方案
  • 唯一ID + 指紋碼
  • token機制
  • redis鎖方案(適合高併發場景)

樂觀鎖方案

具體方法:每次操作時先查version,操作的時候帶上version。

update ... set ...,version=version+1 where version=1;

當操作時發現version!=1說明已經被修改過了,即已經被消費過了,所以不需要繼續操作,直接返回即可,反過來,version=1說明還沒有被消費,可以繼續操作。

唯一ID + 指紋碼(唯一主鍵)

原理是利用數據庫主鍵去重,業務完成後插入主鍵標識。

select count(1) from 表 where ID=唯一ID+指紋碼

唯一ID就是業務表的唯一的主鍵,如商品ID; 指紋碼就是爲了區別每次正常操作的碼,每次操作時生成指紋碼;可以用時間戳+業務編號的方式。

返回值爲0,表示沒操作過,可以繼續操作;
返回值>0,表示已被操作,直接返回。

缺點:時間差問題,即在查詢結束到操作結束的這段時間,可能會有別的用戶操作同一條數據。所以不推薦使用

token機制(token+redis)

1)Client獲取token;
2)Server將token存入redis;
3)Server返回token給Client;
4)判斷token是否存在於redis中,若不存在,則說明是重複消費,若token還存在,則代表是第一次操作,可以繼續操作,操作完之後刪除token。

去重表機制

原理:專門建一個表來存儲業務的唯一ID(訂單號+時間戳),如果時間精度爲1分鐘,那麼1分鐘內的重複交易會被取消,

參考鏈接:https://www.toutiao.com/i6666219332915167756/?group_id=6666219332915167756

Redis的setnx命令實現

使用redis做緩存,每一個操作時具有唯一的防重鎖,操作完即刪除。適合高併發場景

if(!redisDBUtil.setnx("delRepeatUserID"+userID,userID,60)){
  //是重複交易,不處理直接返回
}else{
   //執行操作
   ......
   //處理完刪除加的鎖
   redisDBUtil.del("delRepeatUserID"+userID);
}


//加一個緩存攔截,處理前臺點擊一次按鈕請求多次的問題
boolean success = true;
try {
    success = redisDBUtil.setnx("redeem_"+userPin +"_"+ cardId +"_"+ productId, "redeem_"+userPin +"_"+ cardId +"_"+ productId, 2);
}catch (Exception e){
    logger.info("處理贖回操作緩存異常");
}
if(!success){//如果設置緩存失敗,說明5秒內已經處理過,不需要再處理,直接返回
    logger.info("處理贖回設置緩存失敗,重複處理直接返回");
    result.setSuccess(false);
    return result;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章