SpringBoot 中实现订单30分钟自动取消

在涉及到支付的业务时,通常需要实现一个功能:如果用户在生成订单的一定时间内未完成支付,系统将自动取消订单。本文将基于Spring Boot框架实现订单30分钟内未支付自动取消的几种方案,并提供实例代码。

方案一:定时任务

利用@Scheduled注解,我们可以轻松实现定时任务,周期性扫描订单记录,检查未支付的订单,如果有满足三十分钟则进行关闭。

ini 复制代码
@Component
public class OrderSchedule {
    @Autowired
    private OrderService orderService;

    @Scheduled(cron = "0 0/1 * * * ?")
    public void cancelUnpaidOrders() {
        LocalDateTime now = LocalDateTime.now();
        List<Integer> idList = new ArrayList<Integer>();
        List<OrderEntity> orderList = orderService.getOrderList();
        orderList.forEach(order -> {
            if (order.getWhenCreated().plusMinutes(30).isBefore(now)) {
                idList.add(order.getId());
          }
        });
        orderService.cancelOrderList(idList);
        }
}

方案二:延迟队列

使用消息队列的延迟队列,当订单生成时将订单ID推送到延迟队列,设置30分钟后过期,过期后消费该消息,判断订单状态,如果未支付则取消订单。

typescript 复制代码
@Service
public class OrderService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void createOrder(Order order) {
        // 保存数据库
        saveOrder(order);

        // 将订单ID推送至延迟队列
        rabbitTemplate.convertAndSend("orderDelayExchange", "orderDelayKey", order.getId(), message -> {
            message.getMessageProperties().setDelay(30 * 60 * 1000); // 设置延迟时间
            return message;
        });
    }
}

@Component
public class OrderDelayConsumer {

    @Autowired
    private OrderService orderService;

    @RabbitHandler
    @RabbitListener(queues = "orderDelayQueue")
    public void cancelOrder(String orderId) {
        // 取消订单
        orderService.cancelOrder(orderId);
    }
}

方案三:redis过期事件

使用redis的key过期事件,当订单创建时在Redis中存储一个key,设置30分钟过期,key过期时通过redis的过期事件通知功能触发订单取消。

scss 复制代码
@Service
public class OrderService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    public void createOrder(Order order) {
        // 保存订单至数据库
        saveOrder(order);

        // 在redis中存储一个key,设置30分钟过期
        redisTemplate.opsForValue().set("order:" + order.getId(), order.getId(), 30, TimeUnit.MINUTES);
    }

    // 当key过期时,redis会自动调用该方法(需要配置redis的过期事件通知)
    public void onOrderKeyExpired(String orderId) {
        cancelOrder(orderId);
    }
}

注:redis的key过期通知是一种典型的发布-订阅模式。在redis中,我们可以订阅到某些特定的事件。key过期事件就是其中之一。但想要使用这个功能,需要redis服务器开启相关配置。具体如何配置会在后期的文章里分享给大家。

最后总结:

三种方案都可以实现订单在30分钟内未支付则自动取消的需求。根据实际业务需求、系统负载和其他因素,可以选择最适合自己系统的实现方案。每种方案都有其优缺点,需要根据具体情况权衡。

相关推荐
范闲1 小时前
第三章: 从 ChatModel 到 Agent:Octo 项目的架构演进
后端
江华森1 小时前
深入理解 Flask 实现原理
后端·python·flask
Nturmoils1 小时前
LEFT JOIN 到底什么时候会被优化器偷偷改写成 INNER JOIN
后端
北冥you鱼2 小时前
Go Modules 使用指南:从入门到精通
开发语言·后端·golang
嘟嘟07172 小时前
从零理解 MCP:手写一个本地 MCP Server 并接入 LangChain Agent
前端·后端
沈七2 小时前
Go 补强第三天:给 TaskStore 写单元测试
后端
范闲2 小时前
第二章:Octo v0.1.1:从「能用」到「好用」——终端 AI 聊天体验的全面升级
人工智能·后端
贰先生2 小时前
Xiuno BBS 审计之问题03:附件上传高危风险
后端
Ai拆代码的曹操2 小时前
记一次 K8s Pod Pending 排查:两层坑叠加,从资源到存储的完整复盘
后端
贰先生2 小时前
Xiuno BBS 审计之问题04:Cookie 缺少 HttpOnly/Secure/SameSite 安全属性
后端