国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【安全】Java冪等性校驗(yàn)解決重復(fù)點(diǎn)擊(6種實(shí)現(xiàn)方式)

這篇具有很好參考價(jià)值的文章主要介紹了【安全】Java冪等性校驗(yàn)解決重復(fù)點(diǎn)擊(6種實(shí)現(xiàn)方式)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

一、簡(jiǎn)介

1.1 什么是冪等?

冪等 是一個(gè)數(shù)學(xué)與計(jì)算機(jī)科學(xué)概念,英文 idempotent [a??demp?t?nt]。

  • 在數(shù)學(xué)中,冪等用函數(shù)表達(dá)式就是:f(x) = f(f(x))。比如 求絕對(duì)值 的函數(shù),就是冪等的,abs(x) = abs(abs(x))。
  • 計(jì)算機(jī)科學(xué)中,冪等表示一次和多次請(qǐng)求某一個(gè)資源應(yīng)該具有同樣的作用

滿(mǎn)足冪等條件的性能叫做 冪等性。

1.2 為什么需要冪等性?

我們開(kāi)發(fā)一個(gè)轉(zhuǎn)賬功能,假設(shè)我們調(diào)用下游接口 超時(shí) 了。一般情況下,超時(shí)可能是網(wǎng)絡(luò)傳輸丟包的問(wèn)題,也可能是請(qǐng)求時(shí)沒(méi)送到,還有可能是請(qǐng)求到了,返回結(jié)果卻丟了。這時(shí)候我們是否可以 重試 呢?如果重試的話(huà),是否會(huì)多賺了一筆錢(qián)呢?

【安全】Java冪等性校驗(yàn)解決重復(fù)點(diǎn)擊(6種實(shí)現(xiàn)方式),漏洞掃描,安全,java,開(kāi)發(fā)語(yǔ)言

在我們?nèi)粘i_(kāi)發(fā)中,會(huì)存在各種不同系統(tǒng)之間的相互遠(yuǎn)程調(diào)用。調(diào)用遠(yuǎn)程服務(wù)會(huì)有三個(gè)狀態(tài):成功失敗、超時(shí)。

前兩者都是明確的狀態(tài),但超時(shí)則是 未知狀態(tài)。我們轉(zhuǎn)賬 超時(shí) 的時(shí)候,如果下游轉(zhuǎn)賬系統(tǒng)做好 冪等性校驗(yàn),我們判斷超時(shí)后直接發(fā)起重試,既可以保證轉(zhuǎn)賬正常進(jìn)行,又可以保證不會(huì)多轉(zhuǎn)一筆。

日常開(kāi)發(fā)中,需要考慮冪等性的場(chǎng)景:

  • 前端重復(fù)提交:比如提交 form 表單時(shí),如果快速點(diǎn)擊提交按鈕,就可能產(chǎn)生兩條一樣的數(shù)據(jù)。
  • 用戶(hù)惡意刷單:例如在用戶(hù)投票這種功能時(shí),如果用戶(hù)針對(duì)一個(gè)用戶(hù)進(jìn)行重復(fù)提交投票,這樣會(huì)導(dǎo)致接口接收到用戶(hù)重復(fù)提交的投票信息,會(huì)使投票結(jié)果與事實(shí)嚴(yán)重不符。
  • 接口超時(shí)重復(fù)提交:很多時(shí)候 HTTP 客戶(hù)端工具都默認(rèn)開(kāi)啟超時(shí)重試的機(jī)制,尤其是第三方調(diào)用接口的時(shí)候,為了防止網(wǎng)絡(luò)波動(dòng)等造成的請(qǐng)求失敗,都會(huì)添加重試機(jī)制,導(dǎo)致一個(gè)請(qǐng)求提交多次。
  • MQ重復(fù)消費(fèi):消費(fèi)者讀取消息時(shí),有可能會(huì)讀取到重復(fù)消息。

1.3 接口超時(shí),應(yīng)該如何處理?

如果我們調(diào)用下游接口超時(shí)了,我們應(yīng)該如何處理?其實(shí)從生產(chǎn)者和消費(fèi)者兩個(gè)角度來(lái)看,有兩種方案處理:

  • 方案一:消費(fèi)者角度。在接口超時(shí)后,調(diào)用下游接口檢查數(shù)據(jù)狀態(tài)
    • 如果查詢(xún)到是成功,就走成功流程;
    • 如果是失敗,就按失敗處理(重新請(qǐng)求)。

【安全】Java冪等性校驗(yàn)解決重復(fù)點(diǎn)擊(6種實(shí)現(xiàn)方式),漏洞掃描,安全,java,開(kāi)發(fā)語(yǔ)言

  • 方案二:生產(chǎn)者角度。下游接口支持冪等,上有系統(tǒng)如果調(diào)用超時(shí),發(fā)起重試即可。

【安全】Java冪等性校驗(yàn)解決重復(fù)點(diǎn)擊(6種實(shí)現(xiàn)方式),漏洞掃描,安全,java,開(kāi)發(fā)語(yǔ)言

兩種方案都是可以的,但如果是 MQ重復(fù)消費(fèi)的場(chǎng)景,方案一處理并不是很妥當(dāng),所以我們還是要求下游系統(tǒng) 對(duì)外接口支持冪等。

1.4 冪等性對(duì)系統(tǒng)的影響

冪等性是為了簡(jiǎn)化客戶(hù)端邏輯處理,能防止重復(fù)提交等操作,但卻增加了服務(wù)端的邏輯復(fù)雜性和成本,其主要是:

  • 把并行執(zhí)行的功能改為串行執(zhí)行,降低了執(zhí)行效率。
  • 增加了額外控制冪等的業(yè)務(wù)邏輯,復(fù)雜化了業(yè)務(wù)功能。

在使用前,需要根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景具體分析,除了業(yè)務(wù)上的特殊要求外,一般情況下不需要引入接口的冪等性。

二、Restful API 接口的冪等性

Restful 推薦的幾種 HTTP 接口方法中,不同的請(qǐng)求對(duì)冪等性的要求不同:

請(qǐng)求類(lèi)型 是否冪等 描述
GET GET 方法用于獲取資源。一般不會(huì)也不應(yīng)當(dāng)對(duì)系統(tǒng)資源進(jìn)行改變,所以是冪等的。
POST POST 方法用于創(chuàng)建新的資源。每次執(zhí)行都會(huì)新增數(shù)據(jù),所以不是冪等的。
PUT 不一定 PUT 方法一般用于修改資源。該操作分情況判斷是否滿(mǎn)足冪等,更新中直接根據(jù)某個(gè)值進(jìn)行更新,也能保持冪等。不過(guò)執(zhí)行累加操作的更新是非冪等的。
DELETE 不一定 DELETE 方法一般用于刪除資源。該操作分情況判斷是否滿(mǎn)足冪等,當(dāng)根據(jù)唯一值進(jìn)行刪除時(shí),滿(mǎn)足冪等;但是帶查詢(xún)條件的刪除則不一定滿(mǎn)足。例如:根據(jù)條件刪除一批數(shù)據(jù)后,又有新增數(shù)據(jù)滿(mǎn)足該條件,再執(zhí)行就會(huì)將新增數(shù)據(jù)刪除,需要根據(jù)業(yè)務(wù)判斷是否校驗(yàn)冪等。

三、實(shí)現(xiàn)方式

3.1 數(shù)據(jù)庫(kù)層面,主鍵/唯一索引沖突

日常開(kāi)發(fā)中,為了實(shí)現(xiàn)接口冪等性校驗(yàn),可以這樣實(shí)現(xiàn):

  1. 提前在數(shù)據(jù)庫(kù)中為唯一存在的字段(如:唯一流水號(hào) bizSeq 字段)添加唯一索引,或者直接設(shè)置為主鍵。
  2. 請(qǐng)求過(guò)來(lái),直接將數(shù)據(jù)插入、更新到數(shù)據(jù)庫(kù)中,并進(jìn)行 try-catch 捕獲。
  3. 如果拋出異常,說(shuō)明為重復(fù)請(qǐng)求,可以直接返回成功,或提示請(qǐng)求重復(fù)。

補(bǔ)充: 也可以新建一張 防止重復(fù)點(diǎn)擊表,將唯一標(biāo)識(shí)放到表中,存為主鍵或唯一索引,然后配合 tra-catch 對(duì)重復(fù)點(diǎn)擊的請(qǐng)求進(jìn)行處理。

偽代碼如下:

/**
 * 冪等處理
 */
Rsp idempotent(Request req){
  
    try {
        insert(req);
    } catch (DuplicateKeyException e) {
        //攔截是重復(fù)請(qǐng)求,直接返回成功
        log.info("主鍵沖突,是重復(fù)請(qǐng)求,直接返回成功,流水號(hào):{}",bizSeq);
        return rsp;
    }

    //正常處理請(qǐng)求
    dealRequest(req);

    return rsp;
}

3.2 數(shù)據(jù)庫(kù)層面,樂(lè)觀鎖

樂(lè)觀鎖:樂(lè)觀鎖在操作數(shù)據(jù)時(shí),非常樂(lè)觀,認(rèn)為別人不會(huì)同時(shí)在修改數(shù)據(jù)。因此樂(lè)觀鎖不會(huì)上鎖,只是在執(zhí)行更新的時(shí)候判斷一下,在此期間是否有人修改了數(shù)據(jù)。

樂(lè)觀鎖的實(shí)現(xiàn):

就是給表多加一列 version 版本號(hào),每次更新數(shù)據(jù)前,先查出來(lái)確認(rèn)下是不是剛剛的版本號(hào),沒(méi)有改動(dòng)再去執(zhí)行更新,并升級(jí) version(version=version+1)。

比如,我們更新前,先查一下數(shù)據(jù),查出來(lái)的版本號(hào)是 version=1。

select order_id,version from order where order_id='666'

然后使用 version=1 和 訂單ID 一起作為條件,再去更新:

update order set version = version +1,status='P' where  order_id='666' and version =1

最后,更新成功才可以處理業(yè)務(wù)邏輯,如果更新失敗,默認(rèn)為重復(fù)請(qǐng)求,直接返回。

流程圖如下:

【安全】Java冪等性校驗(yàn)解決重復(fù)點(diǎn)擊(6種實(shí)現(xiàn)方式),漏洞掃描,安全,java,開(kāi)發(fā)語(yǔ)言

為什么版本號(hào)建議自增呢?

因?yàn)闃?lè)觀鎖存在 ABA 的問(wèn)題,如果 version 版本一直是自增的就不會(huì)出現(xiàn) ABA 的情況。

3.3 數(shù)據(jù)庫(kù)層面,悲觀鎖(select for update)【不推薦】

悲觀鎖:通俗點(diǎn)講就是很悲觀,每次去操作數(shù)據(jù)時(shí),都覺(jué)得別人中途會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖。官方點(diǎn)講就是,共享資源每次只給一個(gè)線(xiàn)程使用,其他線(xiàn)程阻塞,用完后再把資源轉(zhuǎn)讓給其它資源。

悲觀鎖的實(shí)現(xiàn):

在訂單業(yè)務(wù)場(chǎng)景中,假設(shè)先查詢(xún)出訂單,如果查到的是處理中狀態(tài),就處理完業(yè)務(wù),然后再更新訂單狀態(tài)為完成。如果查到訂單,并且不是處理中的狀態(tài),則直接返回。

可以使用數(shù)據(jù)庫(kù)悲觀鎖(select … for update)解決這個(gè)問(wèn)題:

begin;  # 1.開(kāi)始事務(wù)
select * from order where order_id='666' for update # 查詢(xún)訂單,判斷狀態(tài),鎖住這條記錄
ifstatus !=處理中){
   //非處理中狀態(tài),直接返回;
   return ;
}
## 處理業(yè)務(wù)邏輯
update order set status='完成' where order_id='666' # 更新完成
commit; # 5.提交事務(wù)

注意:

  • 這里的 order_id 需要是主鍵或索引,只用行級(jí)鎖鎖住這條數(shù)據(jù)即可,如果不是主鍵或索引,會(huì)鎖住整張表。
  • 悲觀鎖在同一事務(wù)操作過(guò)程中,鎖住了一行數(shù)據(jù)。這樣 別的請(qǐng)求過(guò)來(lái)只能等待,如果當(dāng)前事務(wù)耗時(shí)比較長(zhǎng),就很影響接口性能。所以一般 不建議用悲觀鎖的實(shí)現(xiàn)方式。

3.4 數(shù)據(jù)庫(kù)層面,狀態(tài)機(jī)

很多業(yè)務(wù)表,都是由狀態(tài)的,比如:轉(zhuǎn)賬流水表,就會(huì)有 0-待處理,1-處理中,2-成功,3-失敗的狀態(tài)。轉(zhuǎn)賬流水更新的時(shí)候,都會(huì)涉及流水狀態(tài)更新,即涉及 狀態(tài)機(jī)(即狀態(tài)變更圖)。我們可以利用狀態(tài)機(jī)來(lái)實(shí)現(xiàn)冪等性校驗(yàn)。

狀態(tài)機(jī)的實(shí)現(xiàn):

比如:轉(zhuǎn)賬成功后,把 處理中 的轉(zhuǎn)賬流水更新為成功的狀態(tài),SQL 如下:

update transfor_flow set status = 2 where biz_seq='666' and status = 1;

流程圖如下:

【安全】Java冪等性校驗(yàn)解決重復(fù)點(diǎn)擊(6種實(shí)現(xiàn)方式),漏洞掃描,安全,java,開(kāi)發(fā)語(yǔ)言

  • 第1次請(qǐng)求來(lái)時(shí),bizSeq 流水號(hào)是 666,該流水的狀態(tài)是處理中,值是 1,要更新為 2-成功的狀態(tài),所以該 update 語(yǔ)句可以正常更新數(shù)據(jù),sql 執(zhí)行結(jié)果的影響行數(shù)是 1,流水狀態(tài)最后變成了 2。
  • 第2次請(qǐng)求也過(guò)來(lái)了,如果它的流水號(hào)還是 666,因?yàn)樵摿魉疇顟B(tài)已經(jīng)變?yōu)?2-成功的狀態(tài),所以更新結(jié)果是0,不會(huì)再處理業(yè)務(wù)邏輯,接口直接返回。

偽代碼實(shí)現(xiàn)如下:

Rsp idempotentTransfer(Request req){
    String bizSeq = req.getBizSeq();
    int rows= "update transfr_flow set status=2 where biz_seq=#{bizSeq} and status=1;"
    if(rows==1){
        log.info(“更新成功,可以處理該請(qǐng)求”);
        //其他業(yè)務(wù)邏輯處理
        return rsp;
    } else if(rows == 0) {
        log.info(“更新不成功,不處理該請(qǐng)求”);
        //不處理,直接返回
        return rsp;
    }

    log.warn("數(shù)據(jù)異常")
    return rsp:
}

3.5 應(yīng)用層面,token令牌【不推薦】

token 唯一令牌方案一般包括兩個(gè)請(qǐng)求階段:

  1. 客戶(hù)端請(qǐng)求申請(qǐng)獲取請(qǐng)求接口用的token,服務(wù)端生成token返回;
  2. 客戶(hù)端帶著token請(qǐng)求,服務(wù)端校驗(yàn)token。

流程圖如下:

【安全】Java冪等性校驗(yàn)解決重復(fù)點(diǎn)擊(6種實(shí)現(xiàn)方式),漏洞掃描,安全,java,開(kāi)發(fā)語(yǔ)言

  1. 客戶(hù)端發(fā)送請(qǐng)求,申請(qǐng)獲取 token。
  2. 服務(wù)端生成全局唯一的 token,保存到 redis 中(一般會(huì)設(shè)置一個(gè)過(guò)期時(shí)間),然后返回給客戶(hù)端。
  3. 客戶(hù)端帶著 token,發(fā)起請(qǐng)求。
  4. 服務(wù)端去 redis 確認(rèn) token 是否存在,一般用 redis.del(token) 的方式,如果存在會(huì)刪除成功,即處理業(yè)務(wù)邏輯,如果刪除失敗,則直接返回結(jié)果。

補(bǔ)充: 這種方式個(gè)人不推薦,說(shuō)兩方面原因:

  1. 需要前后端聯(lián)調(diào)才能實(shí)現(xiàn),存在溝通成本,最終效果可能與設(shè)想不一致。
  2. 如果前端多次獲取多個(gè) token,還是可以重復(fù)請(qǐng)求的,如果再在獲取 token 處加分布式鎖控制,就不如直接用分布式鎖來(lái)控制冪等性了,即下面這種解決方式。

3.6 應(yīng)用層面,分布式鎖【推薦】

分布式鎖 實(shí)現(xiàn)冪等性的邏輯就是,請(qǐng)求過(guò)來(lái)時(shí),先去嘗試獲取分布式鎖,如果獲取成功,就執(zhí)行業(yè)務(wù)邏輯,反之獲取失敗的話(huà),就舍棄請(qǐng)求直接返回成功。

流程圖如下:

【安全】Java冪等性校驗(yàn)解決重復(fù)點(diǎn)擊(6種實(shí)現(xiàn)方式),漏洞掃描,安全,java,開(kāi)發(fā)語(yǔ)言
  • 分布式鎖可以使用 Redis,也可以使用 Zookeeper,不過(guò) Redis 相對(duì)好點(diǎn),比較輕量級(jí)。
  • Redis 分布式鎖,可以使用 setIfAbsent() 來(lái)實(shí)現(xiàn),注意分布式鎖的 key 必須為業(yè)務(wù)的唯一標(biāo)識(shí)。
  • Redis 執(zhí)行設(shè)置 key 的動(dòng)作時(shí),要設(shè)置過(guò)期時(shí)間,防止釋放鎖失敗。這個(gè)過(guò)期時(shí)間不能太短,太短攔截不了重復(fù)請(qǐng)求,也不能設(shè)置太長(zhǎng),請(qǐng)求量多的話(huà)會(huì)占用存儲(chǔ)空間。

四、Java 代碼實(shí)現(xiàn)

4.1 @NotRepeat 注解

@NotRepeat 注解用于修飾需要進(jìn)行冪等性校驗(yàn)的類(lèi)。

NotRepeat.java

import java.lang.annotation.*;

/**
 * 冪等性校驗(yàn)注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotRepeat {

}

4.2 AOP 切面

AOP切面監(jiān)控被 @Idempotent 注解修飾的方法調(diào)用,實(shí)現(xiàn)冪等性校驗(yàn)邏輯。

IdempotentAOP.java

import com.demo.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * 重復(fù)點(diǎn)擊校驗(yàn)
 */
@Slf4j
@Aspect
@Component
public class IdempotentAOP {
    
    /** Redis前綴 */
    private String API_IDEMPOTENT_CHECK = "API_IDEMPOTENT_CHECK:";

    @Resource
    private HttpServletRequest request;
    @Resource
    private RedisUtils redisUtils;

    /**
     * 定義切面
     */
    @Pointcut("@annotation(com.demo.annotation.NotRepeat)")
    public void notRepeat() {
    }

    /**
     * 在接口原有的方法執(zhí)行前,將會(huì)首先執(zhí)行此處的代碼
     */
    @Before("notRepeat()")
    public void doBefore(JoinPoint joinPoint) {
        String uri = request.getRequestURI();

        // 登錄后才做校驗(yàn)
        UserInfo loginUser = AuthUtil.getLoginUser();
        if (loginUser != null) {
            assert uri != null;
            String key = loginUser.getAccount() + "_" + uri;
            log.info(">>>>>>>>>> 【IDEMPOTENT】開(kāi)始冪等性校驗(yàn),加鎖,account: {},uri: {}", loginUser.getAccount(), uri);

            // 加分布式鎖
            boolean lockSuccess = redisUtils.setIfAbsent(API_IDEMPOTENT_CHECK + key, "1", 30, TimeUnit.MINUTES);
            log.info(">>>>>>>>>> 【IDEMPOTENT】分布式鎖是否加鎖成功:{}", lockSuccess);
            if (!lockSuccess) {
                if (uri.contains("contract/saveDraftContract")) {
                    log.error(">>>>>>>>>> 【IDEMPOTENT】文件保存中,請(qǐng)稍后");
                    throw new IllegalArgumentException("文件保存中,請(qǐng)稍后");

                } else if (uri.contains("contract/saveContract")) {
                    log.error(">>>>>>>>>> 【IDEMPOTENT】文件發(fā)起中,請(qǐng)稍后");
                    throw new IllegalArgumentException("文件發(fā)起中,請(qǐng)稍后");
                }
            }
        }
    }

    /**
     * 在接口原有的方法執(zhí)行后,都會(huì)執(zhí)行此處的代碼(final)
     */
    @After("notRepeat()")
    public void doAfter(JoinPoint joinPoint) {
        // 釋放鎖
        String uri = request.getRequestURI();
        assert uri != null;
        UserInfo loginUser = SysUserUtil.getloginUser();
        if (loginUser != null) {
            String key = loginUser.getAccount() + "_" + uri;
            log.info(">>>>>>>>>> 【IDEMPOTENT】?jī)绲刃孕r?yàn)結(jié)束,釋放鎖,account: {},uri: {}", loginUser.getAccount(), uri);
            redisUtils.del(API_IDEMPOTENT_CHECK + key);
        }
    }
}

4.3 RedisUtils 工具類(lèi)

RedisUtils.java

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;


/**
 * redis工具類(lèi)
 */
@Slf4j
@Component
public class RedisUtils {

    /**
     * 默認(rèn)RedisObjectSerializer序列化
     */
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 加分布式鎖
     */
    public boolean setIfAbsent(String key, String value, long timeout, TimeUnit unit) {
        return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
    }

    /**
     * 釋放鎖
     */
    public void del(String... keys) {
        if (keys != null && keys.length > 0) {
            //將參數(shù)key轉(zhuǎn)為集合
            redisTemplate.delete(Arrays.asList(keys));
        }
    }
}

4.4 測(cè)試類(lèi)

OrderController.java

import com.demo.annotation.NotRepeat;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.List;

/**
 * 冪等性校驗(yàn)測(cè)試類(lèi)
 */
@RequestMapping("/order")
@RestController
public class OrderController {

    @NotRepeat
    @GetMapping("/orderList")
    public List<String> orderList() {
        // 查詢(xún)列表
        return Arrays.asList("Order_A", "Order_B", "Order_C");
        // throw new RuntimeException("參數(shù)錯(cuò)誤");
    }
}

4.5 測(cè)試結(jié)果

請(qǐng)求地址:http://localhost:8080/order/orderList

日志信息如下:

【安全】Java冪等性校驗(yàn)解決重復(fù)點(diǎn)擊(6種實(shí)現(xiàn)方式),漏洞掃描,安全,java,開(kāi)發(fā)語(yǔ)言

經(jīng)測(cè)試,加鎖后,正常處理業(yè)務(wù)、拋出異常都可以正常釋放鎖。

整理完畢,完結(jié)撒花~ ??





參考地址:

1.實(shí)戰(zhàn),實(shí)現(xiàn)冪等的8種方案!https://blog.csdn.net/sufu1065/article/details/122335349

2.Java中的冪等性,https://blog.csdn.net/JewaveOxford/article/details/103578372

3.Spring Boot 實(shí)現(xiàn)接口冪等性的 4 種方案!還有誰(shuí)不會(huì)?https://blog.csdn.net/youanyyou/article/details/114464708文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-744328.html

到了這里,關(guān)于【安全】Java冪等性校驗(yàn)解決重復(fù)點(diǎn)擊(6種實(shí)現(xiàn)方式)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【重復(fù)處理】CRUD接口冪等性處理

    非并發(fā)情況下,查詢(xún)業(yè)務(wù)單號(hào)有沒(méi)有操作過(guò),沒(méi)有則執(zhí)行操作 針對(duì)第一次執(zhí)行業(yè)務(wù)時(shí)間,有大量并發(fā)情況下,整個(gè)操作過(guò)程加鎖,通過(guò)分布式鎖來(lái)加鎖 Select操作:不會(huì)對(duì)業(yè)務(wù)數(shù)據(jù)有影響,天然冪等 Delete操作:第一次已經(jīng)刪除,第二次刪除也不會(huì)有影響 根據(jù)唯一的業(yè)務(wù)號(hào)刪除

    2024年02月12日
    瀏覽(29)
  • RabbitMQ防止消息重復(fù)消費(fèi)、保證異步消息的冪等性

    一、rabbitmq出現(xiàn)消息重復(fù)的場(chǎng)景 1、消費(fèi)成功,沒(méi)有進(jìn)行ack,這時(shí)?Broker?會(huì)重新發(fā)送 2、不確認(rèn)(unack)或 reject?之后,重新排隊(duì),Broker?會(huì)重新發(fā)送 3、消費(fèi)成功,ack時(shí)宕機(jī),沒(méi)有ack成功,消息由unack變?yōu)閞eady,Broker又重新發(fā)送 4、總的來(lái)說(shuō)就是 Broker?發(fā)送消息后,消費(fèi)端收到消息

    2024年02月13日
    瀏覽(23)
  • RabbitMq(七) -- 常見(jiàn)問(wèn)題:冪等性問(wèn)題(消息重復(fù)消費(fèi))、消息丟失

    RabbitMq(七) -- 常見(jiàn)問(wèn)題:冪等性問(wèn)題(消息重復(fù)消費(fèi))、消息丟失

    用戶(hù)對(duì)于同一操作發(fā)起的一次請(qǐng)求或者多次請(qǐng)求的結(jié)果是一致的,不會(huì)因?yàn)槎啻吸c(diǎn)擊而產(chǎn)生了副作用。 舉個(gè)最簡(jiǎn)單的例子,那就是支付,用戶(hù)購(gòu)買(mǎi)商品后支付,支付扣款成功,但是返回結(jié)果的時(shí)候網(wǎng)絡(luò)異常, 此時(shí)錢(qián)已經(jīng)扣了,用戶(hù)再次點(diǎn)擊按鈕,此時(shí)會(huì)進(jìn)行第二次扣款,返

    2024年02月05日
    瀏覽(21)
  • kafka-保證數(shù)據(jù)不重復(fù)-生產(chǎn)者開(kāi)啟冪等性和事務(wù)的作用?

    kafka-保證數(shù)據(jù)不重復(fù)-生產(chǎn)者開(kāi)啟冪等性和事務(wù)的作用?

    適用于消息在寫(xiě)入到服務(wù)器日志后,由于網(wǎng)絡(luò)故障,生產(chǎn)者沒(méi)有及時(shí)收到服務(wù)端的 ACK 消息,生產(chǎn)者誤以為消息沒(méi)有持久化到服務(wù)端,導(dǎo)致生產(chǎn)者重復(fù)發(fā)送該消息,造成了消息的重復(fù)現(xiàn)象,而冪等性就是為了解決該問(wèn)題。 通過(guò)3個(gè)值的唯一性去重: PID:生產(chǎn)者ID 分區(qū)號(hào) seq:?jiǎn)?/p>

    2024年02月14日
    瀏覽(17)
  • Java接口冪等性,如何重試?

    Java接口冪等性,如何重試?

    當(dāng)我們寫(xiě)好一個(gè)項(xiàng)目時(shí),有沒(méi)有深深的思考過(guò),如何處理接口冪等性問(wèn)題呢?今天我們以屈原這句著名詩(shī)句“路漫漫其修遠(yuǎn)兮,吾將上下而求索”的精神來(lái)探索一下這個(gè)問(wèn)題。 冪等性:簡(jiǎn)單來(lái)說(shuō)就是一個(gè)操作多次執(zhí)行的結(jié)果和一次執(zhí)行產(chǎn)生的結(jié)果一致。 答:在計(jì)算機(jī)應(yīng)用中

    2024年02月10日
    瀏覽(21)
  • 騰訊二面:如何保證接口冪等性?高并發(fā)下的接口冪等性如何實(shí)現(xiàn)?

    什么是接口冪等性 接口冪等性這一概念源于數(shù)學(xué),原意是指一個(gè)操作如果連續(xù)執(zhí)行多次所產(chǎn)生的結(jié)果與僅執(zhí)行一次的效果相同,那么我們就稱(chēng)這個(gè)操作是冪等的。在互聯(lián)網(wǎng)領(lǐng)域,特別是在Web服務(wù)、API設(shè)計(jì)和分布式系統(tǒng)中,接口冪等性具有非常重要的意義。 具體到HTTP接口或者

    2024年03月19日
    瀏覽(30)
  • 冪等性設(shè)計(jì)與實(shí)現(xiàn)

    冪等性設(shè)計(jì)與實(shí)現(xiàn)

    冪等性(Idempotence) 是一個(gè)在計(jì)算機(jī)科學(xué)中使用的術(shù)語(yǔ)。當(dāng)某個(gè)操作無(wú)論進(jìn)行一次或多次都產(chǎn)生相同的結(jié)果,我們就說(shuō)這個(gè)操作是冪等的。 例如,刪除文件的操作就是冪等的,因?yàn)闊o(wú)論你嘗試刪除一次還是兩次,結(jié)果都是文件被刪除。相對(duì)地,計(jì)數(shù)器增加操作就不是冪等的,

    2024年02月16日
    瀏覽(25)
  • 一個(gè)注解實(shí)現(xiàn)接口冪等性,真心優(yōu)雅!

    一個(gè)注解實(shí)現(xiàn)接口冪等性,真心優(yōu)雅!

    簡(jiǎn)單來(lái)說(shuō),就是對(duì)一個(gè)接口執(zhí)行重復(fù)的多次請(qǐng)求,與一次請(qǐng)求所產(chǎn)生的結(jié)果是相同的,聽(tīng)起來(lái)非常容易理解,但要真正的在系統(tǒng)中要始終保持這個(gè)目標(biāo),是需要很?chē)?yán)謹(jǐn)?shù)脑O(shè)計(jì)的,在實(shí)際的生產(chǎn)環(huán)境下,我們應(yīng)該保證任何接口都是冪等的,而如何正確的實(shí)現(xiàn)冪等,就是本文要討

    2024年02月03日
    瀏覽(27)
  • 【分布式】: 冪等性和實(shí)現(xiàn)方式

    【分布式】: 冪等性和實(shí)現(xiàn)方式

    冪等(idempotent、idempotence)是一個(gè)數(shù)學(xué)與計(jì)算機(jī)學(xué)概念, 常見(jiàn)于抽象代數(shù)中。在編程中一個(gè)冪等操作的特點(diǎn)是其任意多次執(zhí)行所產(chǎn)生的影響均與一次執(zhí)行的影響相同。冪等函數(shù),或冪等方法,是指可以使用相同參數(shù)重復(fù)執(zhí)行,并能獲得相同結(jié)果的函數(shù)。這些函數(shù)不會(huì)影響系統(tǒng)

    2024年02月08日
    瀏覽(29)
  • rabbitmq+springboot實(shí)現(xiàn)冪等性操作

    文章目錄 1.場(chǎng)景描述 1.1 場(chǎng)景1 1.2 場(chǎng)景2 2.原理 3.實(shí)戰(zhàn)開(kāi)發(fā) 3.1 建表 3.2 集成mybatis-plus 3.3 集成RabbitMq 3.3.1 安裝mq 3.3.2 springBoot集成mq 3.4 具體實(shí)現(xiàn) 3.4.1 mq配置類(lèi) 3.4.2 生產(chǎn)者 3.4.3 消費(fèi)者 消息中間件是分布式系統(tǒng)常用的組件,無(wú)論是異步化、解耦、削峰等都有廣泛的應(yīng)用價(jià)值。我們

    2024年02月10日
    瀏覽(19)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包