业务场景
创建订单10分钟之后自动支付
订单超时取消
…等等…
实现方式
最简单的方式,定时扫表;例如每分钟扫表一次十分钟之后未支付的订单进行主动支付 ; 优点: 简单 缺点: 每分钟全局扫表,浪费资源,有一分钟延迟
使用RabbitMq 实现 RabbitMq实现延迟队列 优点: 开源,现成的稳定的实现方案; 缺点: RabbitMq是一个消息中间件;延迟队列只是其中一个小功能,如果团队技术栈中本来就是使用RabbitMq那还好,如果不是,那为了使用延迟队列而去部署一套RabbitMq成本有点大;
使用Java中的延迟队列,DelayQueue 优点: java.util.concurrent包下一个延迟队列,简单易用;拿来即用 缺点: 单机、不能持久化、宕机任务丢失等等;
本文在这里选用rabbitmq死信队列的方式实现支付超时,取消订单。
1.配置消息队列处开启手动ack 2.定义一个生产者
/**
* 生产者 ->生产消息
* 作者:Chris On 2020/09/01 10:44
* 这里声明的amqpTemplate接口,这个接口包含了发送和接收消息的一般操作,换种说法,它不是某个实现所专有的,所以AMQP存在于名称里。这个接口的实现与AMQP协议的实现紧密关联。
* this.amqpTemplate.convertAndSend的第一个参数为延迟交换机的名称,第二个为延时消费routing-key,第三个参数为order操作对象,第四个参数为消息
*/
@Component
@Slf4j
public class DelaySender {
// AMQP 高级消息队列协议
@Autowired
private AmqpTemplate amqpTemplate;
public void sendDelay(ConcurrentHashMap order) {
log.info("【订单生成时间】" + new Date().toString() +"【1分钟后检查订单是否已经支付】" + order.toString() );
this.amqpTemplate.convertAndSend(DelayRabbitConfig.ORDER_DELAY_EXCHANGE, DelayRabbitConfig.ORDER_DELAY_ROUTING_KEY, order, message -> {
// 如果配置了 params.put("x-message-ttl", 5 * 1000); 那么这一句也可以省略,具体根据业务需要是声明 Queue 的时候就指定好延迟时间还是在发送自己控制时间
message.getMessageProperties().setExpiration(1 * 1000 * 60 + "");
return message;
});
}
}
3.消费者->消费消息,由于我们在配置处开启了手动ack,这里消费者消费到消息后要进行应答,否则消息服务器会以为这条消息没处理掉
/**
* 接收者 ->消费者
* By Chris On 2020/09/01 10:37
*/
@Component
@Slf4j
public class DelayReceiver {
@Resource
private MyOrderMasterMapper myOrderMasterMapper;
@Autowired
private RedisUtil redisUtil;
@Autowired
private SkuMapper skuMapper;
@RabbitListener(queues =