订单到期关闭如何实现
理论上来说,订单到期关闭的实现方式可以有:
- 被动关闭
参考redis键过期策略“惰性删除”的思想,可以在用户访问订单的时候,再去对到期的订单进行关单操作。但系统后往往还有订单列表的查询,只在访问订单时关闭到期订单会使得订单列表查询结果中订单状态不准确。所以这种方式不合适。 - 定时任务
参考redis键过期策略“定期删除”的思想,可以长期维护一个异步线程定期扫描订单表,对到期订单进行关单操作。可以配合xxljob实现。确定是轮询有时间间隔导致到期时间不精确,频繁扫描数据库表也增加了数据库的压力。这种也不合适。 - MQ延迟队列
大多数MQ都支持延迟队列,可以在订单生成时向MQ发送一个带过期时间的消息,一个MQ消费者监听延迟队列,订单消息到期时,MQ关单消费者接收到订单消息,对订单进行关单操作。 - Redisson延迟队列
基于Redis的zset实现的延迟队列也可以做到MQ延迟队列的功能。
RabbitMQ延迟队列实现
使用RabbitMQ延迟队列实现的过程是:
- 向普通交换机发送一个带有过期时间的消息;
- 交换机根据routekey把带过期时间的消息放入绑定的普通队列中;
- 消息在普通队列中过期时,被发送到普通队列配置的死信交换机;
- 死信交换机根据routekey把过期消息放入绑定的死信队列中;
- 监听死信队列的关单消费者收到过期消息进行关单操作;
@Configuration
public class RabbitConfig {
/**
* 订单延迟队列队列所绑定的交换机
*/
@Bean
DirectExchange orderTtlExchange() {
return (DirectExchange) ExchangeBuilder
.directExchange("order.exchange.ttl")
.durable(true)
.build();
}
/**
* 订单延迟队列
*/
@Bean
public Queue orderTtlQueue() {
return QueueBuilder
.durable("order.queue.ttl")
.build();
}
/**
* 将订单延迟队列绑定到交换机
*/
@Bean
Binding orderTtlBinding(DirectExchange orderTtlDirect, Queue orderTtlQueue) {
return BindingBuilder
.bind(orderTtlQueue)
.to(orderTtlDirect)
.with("order.key.ttl");
}
/**
* 订单消息实际消费队列所绑定的交换机
*/
@Bean
DirectExchange orderExchange() {
return (DirectExchange) ExchangeBuilder
.directExchange("order.exchange.cancel")
.durable(true)
.build();
}
/**
* 订单实际消费队列
*/</