在涉及到支付的业务时,通常需要实现一个功能:如果用户在生成订单的一定时间内未完成支付,系统将自动取消订单。本文将基于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分钟内未支付则自动取消的需求。根据实际业务需求、系统负载和其他因素,可以选择最适合自己系统的实现方案。每种方案都有其优缺点,需要根据具体情况权衡。