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

SpringBoot結合Redis實現(xiàn)防止重復提交訂單的實戰(zhàn)指南

 更新時間:2025年11月12日 08:24:35   作者:狼爺  
重復提交訂單的問題,幾乎每個后端都遇到過,今天咱們就從底層邏輯到實戰(zhàn)代碼,聊聊這個老生常談卻又暗藏玄機的話題,感興趣的小伙伴可以了解下

一次點擊,下單成功;兩次點擊,客服崩潰。

重復提交訂單的問題,幾乎每個后端都遇到過。今天咱們就從底層邏輯到實戰(zhàn)代碼,聊聊這個老生常談卻又暗藏玄機的話題。

一、背景:為什么會重復提交?

先說場景。

用戶點了一次“立即支付”,發(fā)現(xiàn)沒反應,再點一次,結果悲劇發(fā)生:

  • 生成了兩筆訂單;
  • 扣了兩次庫存;
  • 財務對賬炸了鍋。

這還只是正常用戶,有的還會:

  • 前端按鈕沒禁用,點個爽;
  • 支付網(wǎng)關超時自動重試;

于是,后端同學開始加鎖、加冪等、加約束,最后一看,代碼又胖了一圈。

二、常見的防重復提交方案

其實防重復提交的核心目標就一句話:

在一定時間內,確保同一個請求只被處理一次。

從架構層次看,可以分為:

層次方案優(yōu)點缺點
前端層按鈕防抖 / 禁用簡單直觀不可靠,易被跳過
網(wǎng)關層冪等性Key通用實現(xiàn)復雜
服務層Redis分布式鎖高性能需要良好鎖管理
數(shù)據(jù)庫層唯一索引 / 狀態(tài)判斷最穩(wěn)執(zhí)行慢,影響性能

實際生產中,一般會前后端雙保險

前端防抖 + 后端冪等控制。

 三、服務端防重復提交的常見思路

來點干貨。

后端層面常用的方案主要有三種。

方案一:冪等性 Token 機制(推薦)

核心邏輯:

  • 前端先調用 /token 接口,獲取一個隨機 token
  • 請求下單時攜帶該 token;
  • 后端校驗 token 是否已使用;
  • 沒用過 → 處理業(yè)務并標記“已使用”;用過 → 拒絕請求。

非常適合「表單類接口」或「下單支付類接口」。

偽流程

前端請求 token -> 緩存保存 token -> 請求接口時攜帶 token -> 校驗通過一次后刪除 token

方案二:Redis 分布式鎖機制

使用 Redis 的 SETNX(或 Redisson)實現(xiàn)業(yè)務級互斥鎖:

boolean lock = redis.setIfAbsent(key, "1", 5, TimeUnit.SECONDS);
if (!lock) {
    throw new BusinessException("請勿重復提交");
}
try {
    createOrder();
} finally {
    redis.delete(key);
}

比如 key 可設計為:

lock:order:create:userId:123

優(yōu)點:

  • 性能高
  • 實現(xiàn)簡單
  • 適合短時間的防重需求

缺點:

需要注意鎖過期與釋放問題。

方案三:數(shù)據(jù)庫層冪等約束

老實人的方案——數(shù)據(jù)庫唯一索引。

ALTER TABLE t_order ADD UNIQUE KEY uk_order_no (order_no);

或者邏輯判斷:

if (orderRepository.existsByOrderNo(orderNo)) {
    log.info("訂單重復提交: {}", orderNo);
    return;
}

優(yōu)點:穩(wěn)如老狗。

缺點:性能不高,適合作為兜底。

四、綜合方案流程圖

下面是一個比較推薦的方案:

冪等Token + Redis鎖 雙層防護

五、實戰(zhàn)代碼(Spring Boot)

1. 獲取冪等 Token 接口

@RestController
@RequestMapping("/api/token")
public class TokenController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @GetMapping("/generate")
    public String generateToken() {
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set("token:" + token, "1", 10, TimeUnit.MINUTES);
        return token;
    }
}

2. 下單接口(冪等 + Redis鎖)

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

    @Autowired
    private StringRedisTemplate redisTemplate;

    @PostMapping("/create")
    public String createOrder(@RequestHeader("Idempotency-Token") String token,
                              @RequestBody OrderRequest request) {
        String key = "token:" + token;

        // 校驗token是否存在
        Boolean exists = redisTemplate.hasKey(key);
        if (Boolean.FALSE.equals(exists)) {
            throw new BusinessException("請勿重復提交");
        }

        // 刪除token,確保一次性
        redisTemplate.delete(key);

        // 加鎖防并發(fā)
        String lockKey = "lock:order:create:" + request.getUserId();
        Boolean locked = redisTemplate.opsForValue()
                .setIfAbsent(lockKey, "1", 5, TimeUnit.SECONDS);

        if (Boolean.FALSE.equals(locked)) {
            throw new BusinessException("請勿重復點擊");
        }

        try {
            // TODO: 創(chuàng)建訂單邏輯
            return "下單成功";
        } finally {
            redisTemplate.delete(lockKey);
        }
    }
}

六、最佳實踐經(jīng)驗總結

項目建議
Token有效期建議 5~10 分鐘
鎖粒度以用戶ID 或 業(yè)務單號為單位
冪等Key傳遞方式推薦放在 Header 中,例如 Idempotency-Token
數(shù)據(jù)庫層兜底唯一約束防止極端情況
日志建議記錄 Token 與鎖狀態(tài),方便排查

一句話總結:

Redis防快點,數(shù)據(jù)庫防慢點,前端防亂點。

七、總結

層級手段優(yōu)點備注
前端按鈕防抖用戶體驗好僅表層防護
RedisToken + Lock性能高推薦主力方案
數(shù)據(jù)庫唯一約束穩(wěn)定最終兜底

最終結論:

沒有銀彈,只有多層防御。

前端防抖 + 后端冪等 + 數(shù)據(jù)庫約束 = 才是真正的生產級防重復方案。

寫在最后

防重復提交這事,說簡單也簡單,說復雜也復雜。

它考驗的不是寫代碼的能力,而是你對業(yè)務一致性系統(tǒng)冪等性的理解。

下次再有人問你“為什么我點兩次下單按鈕扣了兩次錢”,

你可以淡定地說一句——“兄弟,我們系統(tǒng)現(xiàn)在有冪等鎖,不怕你點三次。”

到此這篇關于SpringBoot結合Redis實現(xiàn)防止重復提交訂單的實戰(zhàn)指南的文章就介紹到這了,更多相關SpringBoot防止重復提交訂單內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • springboot自定義配置及自定義對象映射的全流程

    springboot自定義配置及自定義對象映射的全流程

    這篇文章主要介紹了springboot自定義配置及自定義對象映射的全流程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • mybatis 解決從列名到屬性名的自動映射失敗問題

    mybatis 解決從列名到屬性名的自動映射失敗問題

    這篇文章主要介紹了mybatis 解決從列名到屬性名的自動映射失敗問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 兩張動圖--帶你搞懂TCP的三次握手與四次揮手

    兩張動圖--帶你搞懂TCP的三次握手與四次揮手

    TCP是一種傳輸控制協(xié)議,是面向連接的、可靠的、基于字節(jié)流之間的傳輸層通信協(xié)議,由IETF的RFC 793定義。在簡化的計算機網(wǎng)絡OSI模型中,TCP完成第四層傳輸層所指定的功能
    2021-06-06
  • SpringBoot項目中定時器的實現(xiàn)示例

    SpringBoot項目中定時器的實現(xiàn)示例

    在Spring?Boot項目中,你可以使用Spring框架提供的@Scheduled注解來編寫定時任務,本文就來介紹一下SpringBoot項目中定時器的實現(xiàn),感興趣的可以了解一下
    2023-11-11
  • Java利用泛型實現(xiàn)折半查找法

    Java利用泛型實現(xiàn)折半查找法

    泛型是JAVA重要的特性,使用泛型編程,可以使代碼復用率提高。查找作為泛型的一個簡單應用,本文將使用泛型實現(xiàn)折半查找法,感興趣的可以了解一下
    2022-08-08
  • eclipse中沒有SERVER的解決辦法(超詳細)

    eclipse中沒有SERVER的解決辦法(超詳細)

    使用eclipse進行tomcat配置時,經(jīng)常會發(fā)現(xiàn)一個重要的問題就是打開eclipse之后沒有了server選項,所以本給大家詳細介紹了eclipse中沒有SERVER的解決辦法,文中有詳細的圖文講解,需要的朋友可以參考下
    2023-12-12
  • MyBatis環(huán)境資源配置實現(xiàn)代碼詳解

    MyBatis環(huán)境資源配置實現(xiàn)代碼詳解

    這篇文章主要介紹了MyBatis環(huán)境資源配置實現(xiàn)代碼解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-08-08
  • Java拆裝箱深度剖析

    Java拆裝箱深度剖析

    這篇文章主要為大家深度剖析了Java拆箱裝箱的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • java實現(xiàn)微信小程序加密數(shù)據(jù)解密算法

    java實現(xiàn)微信小程序加密數(shù)據(jù)解密算法

    這篇文章主要為大家詳細介紹了java實現(xiàn)微信小程序加密數(shù)據(jù)解密算法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • SpringBoot數(shù)據(jù)脫敏的實現(xiàn)示例

    SpringBoot數(shù)據(jù)脫敏的實現(xiàn)示例

    數(shù)據(jù)脫敏主要應用在客戶安全數(shù)據(jù)或商業(yè)性敏感數(shù)據(jù)的情況,本文主要介紹了SpringBoot數(shù)據(jù)脫敏的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-05-05

最新評論

宜宾县| 宝鸡市| 佛冈县| 全椒县| 塔城市| 双江| 桐乡市| 来安县| 格尔木市| 炉霍县| 乌审旗| 宁海县| 湖口县| 怀集县| 密山市| 乡宁县| 大兴区| 甘孜县| 兴化市| 赞皇县| 武山县| 衡水市| 墨竹工卡县| 岳普湖县| 嘉义县| 金门县| 峨边| 阜新市| 文山县| 曲周县| 柳河县| 横峰县| 绥芬河市| 达尔| 郎溪县| 华宁县| 泰来县| 隆尧县| 开远市| 邹城市| 海阳市|