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

Java防止重復(fù)提交訂單的實(shí)現(xiàn)示例

 更新時(shí)間:2025年11月12日 09:33:33   作者:天天摸魚的java工程師  
本文主要介紹了Java防止重復(fù)提交訂單的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、背景介紹:為什么會(huì)產(chǎn)生重復(fù)提交?

在電商平臺(tái)中,用戶提交訂單是一個(gè)非常敏感的動(dòng)作。這通常涉及:

  • 庫存扣減
  • 優(yōu)惠券核銷
  • 支付下單
  • 消息發(fā)送

但用戶總喜歡:

  • 點(diǎn)兩次“提交訂單”按鈕
  • 網(wǎng)絡(luò)卡頓時(shí)刷新頁面
  • 使用瀏覽器回退再次提交

結(jié)果就是:重復(fù)提交訂單,造成資源浪費(fèi),甚至業(yè)務(wù)損失!

二、問題分析:重復(fù)提交的常見場景

場景示例
用戶行為多次點(diǎn)擊按鈕、瀏覽器刷新
接口冪等性差接口無冪等校驗(yàn),每次都生成新訂單
網(wǎng)絡(luò)重試客戶端自動(dòng)重發(fā)請(qǐng)求(如超時(shí))
分布式系統(tǒng)多個(gè)節(jié)點(diǎn)并發(fā)處理同一訂單請(qǐng)求

三、防止重復(fù)提交的核心原則

要解決重復(fù)提交問題,必須從接口冪等性 + 請(qǐng)求唯一性 + 服務(wù)端鎖控制三方面入手:

  1. 控制請(qǐng)求的唯一標(biāo)識(shí)(token/nonce)
  2. 對(duì)訂單操作進(jìn)行冪等處理
  3. 引入緩存或分布式鎖限制重復(fù)提交

四、解決方案:基于Token機(jī)制 + Redis鎖的防重復(fù)提交設(shè)計(jì)

? 設(shè)計(jì)思路:

  1. 前端在創(chuàng)建訂單前從服務(wù)端獲取一個(gè)唯一 token(防重復(fù)提交標(biāo)識(shí))
  2. 提交訂單時(shí)將 token 附帶傳入
  3. 后端驗(yàn)證 token 是否存在(Redis)
  4. 校驗(yàn)通過 → 執(zhí)行下單邏輯 → 刪除 token
  5. 若 token 已被使用 → 拒絕重復(fù)提交

五、代碼實(shí)現(xiàn)(Spring Boot + Redis)

1. 前端獲取防重復(fù)提交 Token 接口

@RestController
@RequestMapping("/api/order")
public class OrderTokenController {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @GetMapping("/token")
    public ResponseEntity<String> getToken() {
        String token = UUID.randomUUID().toString();
        String key = "order:token:" + token;

        // 設(shè)置有效期5分鐘
        redisTemplate.opsForValue().set(key, "valid", Duration.ofMinutes(5));

        return ResponseEntity.ok(token);
    }
}

2. 提交訂單接口(驗(yàn)證token + 刪除token)

@RestController
@RequestMapping("/api/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @PostMapping("/submit")
    public ResponseEntity<String> submitOrder(@RequestBody OrderRequest request,
                                              @RequestHeader("X-Order-Token") String token) {
        boolean success = orderService.submitOrder(request, token);
        if (success) {
            return ResponseEntity.ok("訂單提交成功");
        } else {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("請(qǐng)勿重復(fù)提交訂單");
        }
    }
}

3. OrderService 實(shí)現(xiàn)防重復(fù)提交邏輯

@Service
public class OrderService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 提交訂單接口,防止重復(fù)提交
     */
    public boolean submitOrder(OrderRequest request, String token) {
        String redisKey = "order:token:" + token;

        // 利用 Redis 的 delete + check 保證冪等性(原子性)
        Boolean result = redisTemplate.delete(redisKey);

        if (Boolean.TRUE.equals(result)) {
            // token存在并刪除 → 第一次提交
            // 執(zhí)行正常訂單創(chuàng)建邏輯
            createOrder(request);
            return true;
        } else {
            // token 不存在 → 重復(fù)提交
            return false;
        }
    }

    private void createOrder(OrderRequest request) {
        // 實(shí)際業(yè)務(wù)處理:生成訂單號(hào)、校驗(yàn)庫存、扣減庫存、寫庫、發(fā)MQ等
        System.out.println("處理訂單:" + request);
    }
}

4. 請(qǐng)求對(duì)象 OrderRequest 示例

@Data
public class OrderRequest {
    private Long userId;
    private List<Long> productIds;
    private BigDecimal totalAmount;
}

六、進(jìn)階優(yōu)化建議

1. 使用 Lua 腳本保證 Redis 操作原子性

Redis delete 操作不是強(qiáng)原子性的,建議使用 Lua 腳本執(zhí)行 “判斷 + 刪除” 邏輯。

// Lua 腳本實(shí)現(xiàn)原子刪除
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                "return redis.call('del', KEYS[1]) else return 0 end";

DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(script);
redisScript.setResultType(Long.class);

Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), "valid");

2. 給訂單接口加限流或熔斷保護(hù)(如 Sentinel)

  • 防止惡意刷接口
  • 降低重復(fù)提交帶來的系統(tǒng)壓力

3. 數(shù)據(jù)庫層冪等校驗(yàn)(雙保險(xiǎn))

即便應(yīng)用層失效,也可以通過數(shù)據(jù)庫約束(如訂單號(hào)唯一)+ INSERT IGNOREON DUPLICATE KEY 防止重復(fù)插入。

七、總結(jié)

面對(duì)用戶重復(fù)提交訂單的問題,我們不能只靠前端“禁用按鈕”了,而是應(yīng)該從后端保障:

  • 請(qǐng)求唯一性
  • 接口冪等性
  • 服務(wù)端鎖機(jī)制

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

  • Redis 是處理冪等控制的利器
  • token機(jī)制簡單實(shí)用,適用于下單、支付、秒殺等場景
  • 多層防御更安全:應(yīng)用層 + 數(shù)據(jù)庫層

?? 最后

到此這篇關(guān)于Java防止重復(fù)提交訂單的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Java防止重復(fù)提交訂單內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java面向程序的三大特性之封裝、繼承、多態(tài)詳解(最新整理)

    Java面向程序的三大特性之封裝、繼承、多態(tài)詳解(最新整理)

    面向?qū)ο蟪绦蛉筇匦裕悍庋b、繼承、多態(tài),而類和對(duì)象階段,主要研究的就是封裝特性,何為封裝呢?簡單來說就是套殼屏蔽細(xì)節(jié),本文給大家介紹Java面向程序的三大特性之封裝、繼承、多態(tài),感興趣的朋友一起看看吧
    2025-06-06
  • Java遞歸算法經(jīng)典實(shí)例(經(jīng)典兔子問題)

    Java遞歸算法經(jīng)典實(shí)例(經(jīng)典兔子問題)

    本文主要對(duì)經(jīng)典的兔子案例分析,來進(jìn)一步更好的理解和學(xué)習(xí)java遞歸算法,具有很好的參考價(jià)值,需要的朋友一起來看下吧
    2016-12-12
  • Springboot項(xiàng)目瘦身之如何將jar包與lib依賴分開打包

    Springboot項(xiàng)目瘦身之如何將jar包與lib依賴分開打包

    這篇文章主要介紹了Springboot項(xiàng)目瘦身之如何將jar包與lib依賴分開打包問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Java實(shí)現(xiàn)swf圖片轉(zhuǎn)pdf的示例代碼

    Java實(shí)現(xiàn)swf圖片轉(zhuǎn)pdf的示例代碼

    本文介紹了一種將SWF文件中的多張圖片提取并轉(zhuǎn)換為PDF文件的方法,首先,通過pom依賴提取SWF文件中的圖片,然后將這些圖片轉(zhuǎn)換為PDF格式,整個(gè)過程中,詳細(xì)測試了該方法的可行性和有效性,需要的朋友可以參考下
    2026-05-05
  • springboot接口接收數(shù)組及多個(gè)參數(shù)的問題及解決

    springboot接口接收數(shù)組及多個(gè)參數(shù)的問題及解決

    這篇文章主要介紹了springboot接口接收數(shù)組及多個(gè)參數(shù)的問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • SpringBoot整合MOTT動(dòng)態(tài)讀取數(shù)據(jù)庫連接信息并連接MQTT服務(wù)端

    SpringBoot整合MOTT動(dòng)態(tài)讀取數(shù)據(jù)庫連接信息并連接MQTT服務(wù)端

    MQTT是一種輕量級(jí)的消息傳輸協(xié)議(Message Queuing Telemetry Transport),旨在實(shí)現(xiàn)設(shè)備之間的低帶寬和高延遲的通信,本文給大家介紹了SpringBoot整合MOTT動(dòng)態(tài)讀取數(shù)據(jù)庫連接信息并連接MQTT服務(wù)端,需要的朋友可以參考下
    2024-04-04
  • Java中Integer.equals的用法與特殊情況

    Java中Integer.equals的用法與特殊情況

    Java中Integer.equals比較數(shù)值而非對(duì)象地址,自動(dòng)裝箱處理int參數(shù),-128~127范圍內(nèi)使用==安全,超出范圍或null需用Objects.equals,compareTo用于大小比較,equals僅判斷相等性,注意類型不匹配會(huì)導(dǎo)致false
    2025-07-07
  • Java實(shí)戰(zhàn)小技巧之?dāng)?shù)組與list互轉(zhuǎn)

    Java實(shí)戰(zhàn)小技巧之?dāng)?shù)組與list互轉(zhuǎn)

    在Java中,經(jīng)常遇到需要List與數(shù)組互相轉(zhuǎn)換的場景,下面這篇文章主要給大家介紹了關(guān)于Java實(shí)戰(zhàn)小技巧之?dāng)?shù)組與list互轉(zhuǎn)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-08-08
  • SpringBoot集合Mybatis過程解析

    SpringBoot集合Mybatis過程解析

    這篇文章主要介紹了SpringBoot集合Mybatis過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • IDEA類存在但找不到的解決辦法

    IDEA類存在但找不到的解決辦法

    本文主要介紹了IDEA類存在但找不到的解決辦法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07

最新評(píng)論

鲁甸县| 军事| 芜湖县| 茌平县| 新野县| 项城市| 庆元县| 湘西| 深水埗区| 房产| 石城县| 平谷区| 喀喇沁旗| 宕昌县| 浮梁县| 上虞市| 吉安县| 鄱阳县| 台州市| 涞水县| 沂南县| 衡南县| 都兰县| 衡水市| 航空| 密山市| 太湖县| 田林县| 基隆市| 鹤峰县| 奉化市| 合江县| 定结县| 阜城县| 山东省| 平邑县| 荥经县| 定陶县| 桂平市| 静安区| 和田县|