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

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

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

一次點(diǎn)擊,下單成功;兩次點(diǎn)擊,客服崩潰。

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

一、背景:為什么會重復(fù)提交?

先說場景。

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

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

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

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

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

二、常見的防重復(fù)提交方案

其實(shí)防重復(fù)提交的核心目標(biāo)就一句話:

在一定時間內(nèi),確保同一個請求只被處理一次。

從架構(gòu)層次看,可以分為:

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

實(shí)際生產(chǎn)中,一般會前后端雙保險

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

 三、服務(wù)端防重復(fù)提交的常見思路

來點(diǎn)干貨。

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

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

核心邏輯:

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

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

偽流程

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

方案二:Redis 分布式鎖機(jī)制

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

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

比如 key 可設(shè)計為:

lock:order:create:userId:123

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

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

缺點(diǎn):

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

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

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

ALTER TABLE t_order ADD UNIQUE KEY uk_order_no (order_no);

或者邏輯判斷:

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

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

缺點(diǎn):性能不高,適合作為兜底。

四、綜合方案流程圖

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

冪等Token + Redis鎖 雙層防護(hù)

五、實(shí)戰(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;

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

        // 刪除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("請勿重復(fù)點(diǎn)擊");
        }

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

六、最佳實(shí)踐經(jīng)驗(yàn)總結(jié)

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

一句話總結(jié):

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

七、總結(jié)

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

最終結(jié)論:

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

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

寫在最后

防重復(fù)提交這事,說簡單也簡單,說復(fù)雜也復(fù)雜。

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

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

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Java拆裝箱深度剖析

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

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

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

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

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

最新評論

六枝特区| 莒南县| 柯坪县| 宝应县| 淮阳县| 桑日县| 高台县| 甘谷县| 富顺县| 准格尔旗| 安西县| 分宜县| 平谷区| 塘沽区| 黎平县| 黑山县| 新化县| 洪泽县| 浦北县| 五大连池市| 鞍山市| 孝感市| 临城县| 九龙坡区| 龙游县| 繁昌县| 麟游县| 铁力市| 宜春市| 梅州市| 滦南县| 龙口市| 长泰县| 孙吴县| 柳林县| 赞皇县| 丰宁| 济宁市| 扬州市| 凌源市| 九龙城区|