欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot訂單超時(shí)自動(dòng)取消的三種主流實(shí)現(xiàn)方案

 更新時(shí)間:2025年07月23日 09:33:47   作者:半部論語(yǔ)  
在電商、外賣(mài)、票務(wù)等業(yè)務(wù)中,下單后若 30 分鐘未支付則自動(dòng)取消是一道經(jīng)典需求,實(shí)現(xiàn)方式既要保證 實(shí)時(shí)性,又要在 高并發(fā) 下保持 低成本、高可靠,本文基于 Spring Boot,給出 3 種生產(chǎn)級(jí)落地方案,并附完整代碼與選型對(duì)比,需要的朋友可以參考下

引言

在電商、外賣(mài)、票務(wù)等業(yè)務(wù)中,“下單后若 30 分鐘未支付則自動(dòng)取消”是一道經(jīng)典需求。實(shí)現(xiàn)方式既要保證 實(shí)時(shí)性,又要在 高并發(fā) 下保持 低成本、高可靠

本文基于 Spring Boot,給出 3 種生產(chǎn)級(jí)落地方案,并附完整代碼與選型對(duì)比,方便快速?zèng)Q策。

一、需求拆解

功能點(diǎn)約束
觸發(fā)條件創(chuàng)建時(shí)間 + 30 min 仍未支付
實(shí)時(shí)性秒級(jí)(理想) / 分鐘級(jí)(可接受)
冪等重復(fù)取消需冪等
高并發(fā)峰值 10 w+/日
數(shù)據(jù)一致性不能漏單、不能錯(cuò)單

二、方案總覽

方案核心機(jī)制實(shí)時(shí)性額外組件代碼復(fù)雜度
① 定時(shí)任務(wù)@Scheduled + DB 掃描分鐘級(jí)無(wú)★☆☆
② 延遲隊(duì)列RabbitMQ TTL + DLX秒級(jí)RabbitMQ★★☆
③ Redis 過(guò)期事件Key TTL + Keyspace Notify秒級(jí)Redis★★☆

三、方案 1:定時(shí)任務(wù)(@Scheduled)

1. 思路

周期性?huà)呙栌唵伪恚?ldquo;創(chuàng)建時(shí)間 + 30 min < 當(dāng)前時(shí)間”且狀態(tài)為 PENDING 的訂單置為 CANCELLED。

2. 代碼實(shí)現(xiàn)

@EnableScheduling
@Component
@RequiredArgsConstructor
public class OrderCancelSchedule {

    private final OrderService orderService;

    /** 每 30s 跑一次,可根據(jù)數(shù)據(jù)量調(diào)整 */
    @Scheduled(fixedDelay = 30_000)
    public void cancelUnpaidOrders() {
        LocalDateTime expirePoint = LocalDateTime.now().minusMinutes(30);
        List<Long> ids = orderService.findUnpaidBefore(expirePoint);
        if (!ids.isEmpty()) {
            int affected = orderService.batchCancel(ids);
            log.info("自動(dòng)取消訂單 {} 條", affected);
        }
    }
}

3. 優(yōu)化技巧

  • 分頁(yè) + 索引
CREATE INDEX idx_order_status_created ON t_order(status, created_time);
  • 分片掃描:按 ID 或時(shí)間分片,避免大表鎖。
  • 單機(jī)多線(xiàn)程@Async("cancelExecutor") + 線(xiàn)程池。

4. 優(yōu)缺點(diǎn)

  • ? 零依賴(lài)、實(shí)現(xiàn)快
  • ? 數(shù)據(jù)量大時(shí) DB 壓力大;實(shí)時(shí)性受輪詢(xún)間隔限制

5. 適用場(chǎng)景

日訂單 < 1 w,或作為兜底方案。

四、方案 2:RabbitMQ 延遲隊(duì)列

1. 思路

訂單創(chuàng)建后發(fā)送一條 30 min TTL 的消息;到期自動(dòng)路由到消費(fèi)隊(duì)列,消費(fèi)者檢查訂單狀態(tài)并取消。

2. 架構(gòu)圖

Producer ──> Delay Exchange (x-delayed-message) ──> 30min TTL ──> Cancel Queue ──> Consumer

3. 代碼實(shí)現(xiàn)

3.1 聲明交換機(jī) & 隊(duì)列

@Configuration
public class RabbitDelayConfig {

    @Bean
    public CustomExchange delayExchange() {
        Map<String, Object> args = Map.of("x-delayed-type", "direct");
        return new CustomExchange("order.delay", "x-delayed-message", true, false, args);
    }

    @Bean
    public Queue cancelQueue() {
        return QueueBuilder.durable("order.cancel.queue").build();
    }

    @Bean
    public Binding binding() {
        return BindingBuilder.bind(cancelQueue()).to(delayExchange()).with("order.cancel").noargs();
    }
}

3.2 發(fā)送延遲消息

@Service
@RequiredArgsConstructor
public class OrderPublisher {
    private final RabbitTemplate rabbitTemplate;

    public void createOrder(Order order) {
        // 1. 落庫(kù)
        orderMapper.insert(order);
        // 2. 發(fā)送延遲消息
        rabbitTemplate.convertAndSend(
            "order.delay",
            "order.cancel",
            order.getId(),
            msg -> {
                msg.getMessageProperties().setDelay(30 * 60 * 1000); // 30 min
                return msg;
            }
        );
    }
}

3.3 消費(fèi)并取消

@Component
@RabbitListener(queues = "order.cancel.queue")
public class CancelConsumer {
    private final OrderService orderService;

    @RabbitHandler
    public void handle(Long orderId) {
        Order order = orderService.find(orderId);
        if (order != null && order.getStatus() == OrderStatus.PENDING) {
            orderService.cancel(orderId);
        }
    }
}

4. 優(yōu)缺點(diǎn)

  • ? 實(shí)時(shí)性好(秒級(jí));支持分布式;消息持久化
  • ? 需要 RabbitMQ;鏈路更長(zhǎng)

5. 適用場(chǎng)景

中高并發(fā),需秒級(jí)取消,已用 MQ 或愿意引入 MQ。

五、方案 3:Redis Keyspace 過(guò)期事件

1. 思路

order:{id} 作為 key,30 min TTL;Redis 鍵過(guò)期時(shí)推送事件;應(yīng)用監(jiān)聽(tīng)后取消訂單。

2. Redis 配置

# redis.conf
notify-keyspace-events Ex

或 CLI:

CONFIG SET notify-keyspace-events Ex

3. 代碼實(shí)現(xiàn)

3.1 訂單創(chuàng)建時(shí)寫(xiě) Redis

@Service
public class OrderService {
    private final StringRedisTemplate redisTemplate;

    public void createOrder(Order order) {
        orderMapper.insert(order);
        // value 隨意,這里用 id
        redisTemplate.opsForValue()
          .set("order:" + order.getId(),
               String.valueOf(order.getId()),
               Duration.ofMinutes(30));
    }
}

3.2 監(jiān)聽(tīng)過(guò)期事件

@Configuration
public class RedisListenerConfig {

    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory cf) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(cf);
        container.addMessageListener(
            (message, pattern) -> {
                String key = message.toString();
                if (key.startsWith("order:")) {
                    String orderId = key.substring(6);
                    // 冪等取消
                    orderService.cancelIfUnpaid(Long.valueOf(orderId));
                }
            },
            new PatternTopic("__keyevent@*__:expired")
        );
        return container;
    }
}

4. 冪等 & 可靠性

  • 冪等:取消 SQL 加狀態(tài)條件 WHERE status = PENDING。
  • 可靠性:Redis 重啟會(huì)丟失未過(guò)期 key,需 兜底定時(shí)任務(wù)(方案 1)雙保險(xiǎn)。

5. 優(yōu)缺點(diǎn)

  • ? 實(shí)時(shí)性高,組件少
  • ? Redis 重啟可能丟事件;需處理冪等

6. 適用場(chǎng)景

已用 Redis,訂單量中等,能接受極低概率漏單。

六、3 種方案對(duì)比與選型

維度定時(shí)任務(wù)RabbitMQ 延遲隊(duì)列Redis 過(guò)期事件
實(shí)時(shí)性分鐘級(jí)秒級(jí)秒級(jí)
吞吐量
額外組件無(wú)RabbitMQRedis
可靠性中(需兜底)
實(shí)現(xiàn)復(fù)雜度★☆☆★★☆★★☆
推薦場(chǎng)景小流量、兜底高并發(fā)、已用 MQ已用 Redis、中等并發(fā)

建議

  1. 小項(xiàng)目 → 定時(shí)任務(wù)即可;
  2. 大流量 → 延遲隊(duì)列;
  3. 已用 Redis → 過(guò)期事件 + 定時(shí)任務(wù)兜底雙保險(xiǎn)。

七、灰度 & 監(jiān)控

  • 灰度發(fā)布:按用戶(hù)尾號(hào)或城市分批切換方案。
  • 監(jiān)控指標(biāo)
    • 取消成功率
    • MQ 消息積壓
    • Redis 過(guò)期 QPS
    • 定時(shí)任務(wù)掃描耗時(shí)

八、小結(jié)

一句話(huà)總結(jié)定時(shí)任務(wù) 簡(jiǎn)單但慢;延遲隊(duì)列 實(shí)時(shí)但重;Redis 過(guò)期 輕量但需兜底。

在實(shí)際落地中,可以 并行運(yùn)行 兩種方案(如延遲隊(duì)列 + 兜底定時(shí)任務(wù)),通過(guò)配置開(kāi)關(guān)靈活切換,確保業(yè)務(wù)永遠(yuǎn)在線(xiàn)。祝你的訂單永不超賣(mài)!

以上就是SpringBoot訂單超時(shí)自動(dòng)取消的三種主流實(shí)現(xiàn)方案的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot訂單超時(shí)自動(dòng)取消的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論