最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

對(duì)Java接口進(jìn)行冪等性控制的三種方法

 更新時(shí)間:2025年06月24日 10:08:14   作者:天天摸魚(yú)的java工程師  
在做分布式系統(tǒng)、支付系統(tǒng)、電商秒殺等實(shí)際項(xiàng)目中,我們經(jīng)常會(huì)遇到接口被重復(fù)調(diào)用的問(wèn)題,像用戶(hù)支付時(shí)多次點(diǎn)擊“支付”按鈕,消息隊(duì)列消費(fèi)失敗后自動(dòng)重試等,這些行為如果沒(méi)有控制好冪等性,會(huì)產(chǎn)生重復(fù)數(shù)據(jù),所以本文給大家介紹了對(duì)Java接口進(jìn)行冪等性控制的三種方法

前言

在做分布式系統(tǒng)、支付系統(tǒng)、電商秒殺等實(shí)際項(xiàng)目中,我們經(jīng)常會(huì)遇到接口被重復(fù)調(diào)用的問(wèn)題。比如:

  • 用戶(hù)支付時(shí)多次點(diǎn)擊“支付”按鈕;
  • 網(wǎng)絡(luò)重試機(jī)制導(dǎo)致接口多次請(qǐng)求;
  • 消息隊(duì)列消費(fèi)失敗后自動(dòng)重試。

這些行為如果沒(méi)有控制好冪等性,輕則產(chǎn)生重復(fù)數(shù)據(jù),重則產(chǎn)生資金損失、庫(kù)存混亂等嚴(yán)重問(wèn)題。

今天我們深入聊聊:如何在 Java 中實(shí)現(xiàn)接口的冪等性控制?

什么是冪等性?

**冪等性(Idempotent)**是指一個(gè)接口被調(diào)用多次,結(jié)果與調(diào)用一次的效果相同

  • GET /order/123 —— 天然冪等。
  • POST /order/create —— 非冪等,需要控制。

冪等性控制的三大核心手段

在我的項(xiàng)目實(shí)戰(zhàn)中,主要使用以下三種方式實(shí)現(xiàn)接口冪等控制:

  • 數(shù)據(jù)庫(kù)唯一索引控制
  • Redis 防重復(fù)提交
  • 冪等 Token 機(jī)制

下面我們逐個(gè)拆解原理與代碼實(shí)現(xiàn)。

1、數(shù)據(jù)庫(kù)唯一索引控制(經(jīng)典可靠)

原理

利用數(shù)據(jù)庫(kù)的唯一約束,防止插入重復(fù)數(shù)據(jù)。

適用場(chǎng)景

  • 創(chuàng)建訂單、支付單等“只允許一次成功”的業(yè)務(wù)操作。
  • 數(shù)據(jù)庫(kù)操作為最終落地。

實(shí)現(xiàn)

假設(shè)有個(gè)訂單表 order,我們希望一個(gè) clientOrderNo(客戶(hù)端訂單號(hào))只能插入一次。

ALTER TABLE t_order ADD UNIQUE KEY uk_client_order_no (client_order_no);

Java 代碼示例

public void createOrder(String clientOrderNo, OrderDTO dto) {
    try {
        Order order = new Order();
        order.setClientOrderNo(clientOrderNo);
        order.setAmount(dto.getAmount());
        order.setUserId(dto.getUserId());
        orderRepository.insert(order); // 會(huì)觸發(fā)唯一索引約束
    } catch (DuplicateKeyException e) {
        log.warn("訂單已存在,冪等處理: {}", clientOrderNo);
        // 查詢(xún)已有訂單并返回,保持冪等
        Order existing = orderRepository.findByClientOrderNo(clientOrderNo);
        return existing;
    }
}

總結(jié)

優(yōu)點(diǎn):

  • 簡(jiǎn)單可靠,數(shù)據(jù)庫(kù)層強(qiáng)力保證。

缺點(diǎn):

  • 粒度粗,如果涉及復(fù)雜流程(如多表插入)需結(jié)合事務(wù)控制。

2、Redis 防重復(fù)提交(輕量方案)

原理

利用 Redis 的原子性,通過(guò) SETNX 命令設(shè)置唯一鍵,控制某個(gè)請(qǐng)求只處理一次。

適用場(chǎng)景

  • 表單防重復(fù)提交。
  • 接口短時(shí)間內(nèi)禁止重復(fù)請(qǐng)求。

Java 實(shí)現(xiàn)

public boolean tryAcquireRequest(String key, long expireSeconds) {
    // 原子設(shè)置鍵 + 過(guò)期時(shí)間,表示該請(qǐng)求已處理
    return Boolean.TRUE.equals(
        redisTemplate.opsForValue().setIfAbsent(key, "1", Duration.ofSeconds(expireSeconds))
    );
}

Controller 示例

@PostMapping("/api/pay")
public ResponseEntity<?> doPay(@RequestBody PayRequest request) {
    String redisKey = "pay:" + request.getUserId() + ":" + request.getOrderId();

    if (!idempotentService.tryAcquireRequest(redisKey, 30)) {
        return ResponseEntity.status(HttpStatus.CONFLICT).body("重復(fù)請(qǐng)求,請(qǐng)稍后再試");
    }

    // 執(zhí)行支付邏輯
    paymentService.pay(request.getOrderId());

    return ResponseEntity.ok("支付成功");
}

總結(jié)

優(yōu)點(diǎn):

  • 高性能,適合高并發(fā)。
  • 不依賴(lài)數(shù)據(jù)庫(kù)操作。

缺點(diǎn):

  • Redis異常時(shí)無(wú)法保證冪等。
  • 需手動(dòng)構(gòu)造唯一 key。

3、冪等 Token 機(jī)制(前后端協(xié)作)

原理

前端首次請(qǐng)求時(shí)從服務(wù)端獲取一個(gè) token,提交表單時(shí)附帶該 token,服務(wù)端驗(yàn)證 token 是否已被使用。

適用場(chǎng)景

  • 表單提交、下單等需要用戶(hù)主動(dòng)確認(rèn)的操作。
  • 控制用戶(hù)操作行為。

實(shí)現(xiàn)步驟

1. 生成冪等 token(后端)

@GetMapping("/token")
public String generateToken() {
    String token = UUID.randomUUID().toString();
    redisTemplate.opsForValue().set("token:" + token, "1", Duration.ofMinutes(5));
    return token;
}

2. 提交接口驗(yàn)證 token

@PostMapping("/submit")
public ResponseEntity<?> submitForm(@RequestParam String token, @RequestBody FormDTO form) {
    String redisKey = "token:" + token;

    // Redis 的 delete 操作返回 1 表示成功刪除(即 token 存在)
    Boolean success = redisTemplate.delete(redisKey);

    if (Boolean.FALSE.equals(success)) {
        return ResponseEntity.status(HttpStatus.CONFLICT).body("請(qǐng)勿重復(fù)提交");
    }

    // 執(zhí)行業(yè)務(wù)邏輯
    formService.process(form);

    return ResponseEntity.ok("提交成功");
}

總結(jié)

優(yōu)點(diǎn):

  • 精準(zhǔn)控制用戶(hù)行為。
  • 非常適合前后端協(xié)作系統(tǒng)。

缺點(diǎn):

  • 實(shí)現(xiàn)略復(fù)雜,強(qiáng)依賴(lài) Redis。
  • 前端需配合使用。

實(shí)戰(zhàn)建議

方法場(chǎng)景適用冪等級(jí)別復(fù)雜度推薦備注
數(shù)據(jù)庫(kù)唯一索引訂單、支付等數(shù)據(jù)落庫(kù)推薦首選
Redis 防重復(fù)提交高并發(fā)接口、表單提交配合使用
Token 機(jī)制用戶(hù)行為防重復(fù)前后端配合使用

總結(jié)

冪等性控制不是一個(gè)「萬(wàn)能解」,而是需要根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景選擇合適的方案。作為有多年經(jīng)驗(yàn)的后端工程師,我通常會(huì):

  • 數(shù)據(jù)插入場(chǎng)景首選數(shù)據(jù)庫(kù)唯一索引;
  • 接口限流或重復(fù)提交保護(hù)使用 Redis;
  • 用戶(hù)行為防重復(fù)引入 Token 機(jī)制。

冪等性雖“小”,但不控制好,問(wèn)題很“大”。希望本文對(duì)你理解冪等控制的原理和實(shí)現(xiàn)有所幫助。

以上就是對(duì)Java接口進(jìn)行冪等性控制的三種方法的詳細(xì)內(nèi)容,更多關(guān)于Java接口冪等性控制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java生成二維碼的實(shí)現(xiàn)方式匯總

    Java生成二維碼的實(shí)現(xiàn)方式匯總

    本文將基于Spring Boot介紹兩種生成二維碼的實(shí)現(xiàn)方式,一種是基于Google開(kāi)發(fā)工具包,另一種是基于Hutool來(lái)實(shí)現(xiàn),下面我們將基于Spring Boot,并采用兩種方式實(shí)現(xiàn)二維碼的生成,對(duì)于每一種方式還提供兩種類(lèi)型的二維碼返回形式,需要的朋友可以參考下
    2023-09-09
  • IntelliJ IDEA中打開(kāi)拼寫(xiě)檢查與忽略提示曲線的方法

    IntelliJ IDEA中打開(kāi)拼寫(xiě)檢查與忽略提示曲線的方法

    今天小編就為大家分享一篇關(guān)于IntelliJ IDEA中打開(kāi)拼寫(xiě)檢查與忽略提示曲線的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-10-10
  • 分析 Java Stream 的 peek使用實(shí)踐與副作用處理方案

    分析 Java Stream 的 peek使用實(shí)踐與副作用處理方案

    Stream API的peek操作是中間操作,用于觀察元素但不終止流,其副作用風(fēng)險(xiǎn)包括線程安全、順序混亂及性能問(wèn)題,合理使用場(chǎng)景有限,本文給大家介紹Java Stream的peek使用實(shí)踐與副作用,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • springboot整合redis集群過(guò)程解析

    springboot整合redis集群過(guò)程解析

    這篇文章主要介紹了springboot整合redis集群過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • 學(xué)習(xí)Java之異常到底該如何捕獲和處理

    學(xué)習(xí)Java之異常到底該如何捕獲和處理

    我們知道,Java的異常處理是通過(guò)5個(gè)關(guān)鍵字來(lái)實(shí)現(xiàn)的,即try、catch、throw、throws和finally,try?catch語(yǔ)句用于捕獲并處理異常,但具體該怎么捕獲異常,怎么拋出異常,什么時(shí)候拋,什么時(shí)候捕,感興趣的小伙伴跟著小編一起來(lái)看看吧
    2023-08-08
  • Java并發(fā)容器之ConcurrentLinkedQueue詳解

    Java并發(fā)容器之ConcurrentLinkedQueue詳解

    這篇文章主要介紹了Java并發(fā)容器之ConcurrentLinkedQueue詳解,加鎖隊(duì)列的實(shí)現(xiàn)較為簡(jiǎn)單,這里就略過(guò),我們來(lái)重點(diǎn)來(lái)解讀一下非阻塞隊(duì)列,
    從點(diǎn)到面, 下面我們來(lái)看下非阻塞隊(duì)列經(jīng)典實(shí)現(xiàn)類(lèi)ConcurrentLinkedQueue,需要的朋友可以參考下
    2023-12-12
  • SpringBoot詳解整合Spring?Boot?Admin實(shí)現(xiàn)監(jiān)控功能

    SpringBoot詳解整合Spring?Boot?Admin實(shí)現(xiàn)監(jiān)控功能

    這篇文章主要介紹了SpringBoot整合Spring?Boot?Admin實(shí)現(xiàn)服務(wù)監(jiān)控,內(nèi)容包括Server端服務(wù)開(kāi)發(fā),Client端服務(wù)開(kāi)發(fā)其中Spring?Boot?Admin還可以對(duì)其監(jiān)控的服務(wù)提供告警功能,如服務(wù)宕機(jī)時(shí),可以及時(shí)以郵件方式通知運(yùn)維人員,感興趣的朋友跟隨小編一起看看吧
    2022-07-07
  • java 對(duì)稱(chēng)加密算法實(shí)現(xiàn)詳解

    java 對(duì)稱(chēng)加密算法實(shí)現(xiàn)詳解

    這篇文章主要介紹了java 對(duì)稱(chēng)加密算法實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • 15道非常經(jīng)典的Java面試題 附詳細(xì)答案

    15道非常經(jīng)典的Java面試題 附詳細(xì)答案

    這篇文章主要為大家推薦了15道非常經(jīng)典的Java面試題,附詳細(xì)答案,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • Java?Spring讀取和存儲(chǔ)詳細(xì)操作

    Java?Spring讀取和存儲(chǔ)詳細(xì)操作

    這篇文章主要介紹了Spring讀取和存儲(chǔ)詳細(xì)操作,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-08-08

最新評(píng)論

庆云县| 阳原县| 文登市| 开阳县| 开封市| 鸡泽县| 富川| 五莲县| 舞阳县| 紫云| 绥棱县| 高邮市| 东乌珠穆沁旗| 庄河市| 东宁县| 延吉市| 上高县| 德阳市| 武义县| 长宁县| 常熟市| 嘉峪关市| 共和县| 绥德县| 康马县| 灵宝市| 永昌县| 湖北省| 二连浩特市| 博白县| 鹤庆县| 介休市| 海安县| 吉首市| 惠来县| 会理县| 荥经县| 黔东| 博乐市| 枣强县| 淮北市|