赞
踩
前言:这几天在收尾项目,发现对订单超时的业务做的不够细致(下单15分钟后未付款则订单失效),我们选择的是最为简单的定时任务来跑缓存中的订单,并筛选出超时的订单进行数据库更新操作,但是这样太消耗服务器的性能了,所以思考是否有别的解决方案
方案当然是有的,就我个人而言,就知道三种方案
<!--消息队列相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
rabbitmq:
host: localhost # rabbitmq的连接地址
port: 5672 # rabbitmq的连接端口号
virtual-host: /demo # rabbitmq的虚拟host
username: root # rabbitmq的用户名
password: root # rabbitmq的密码
publisher-confirms: true #如果对异步消息需要回调必须设置为true
- 用于延迟消息队列及处理取消订单消息队列的常量定义,包括交换机名称、队列名称、路由键名称。
package com.xxx.xxx.xxx.enume; import lombok.Getter; /** * 消息队列枚举配置 * @author demo */ @Getter public enum QueueEnum { /** * 消息通知队列 */ QUEUE_ORDER_CANCEL("demo.order.direct", "demo.order.cancel", "demo.order.cancel"), /** * 消息通知ttl队列 */ QUEUE_TTL_ORDER_CANCEL("demo.order.direct.ttl", "demo.order.cancel.ttl", "demo.order.cancel.ttl"); /** * 交换名称 */ private String exchange; /** * 队列名称 */ private String name; /** * 路由键 */ private String routeKey; QueueEnum(String exchange, String name, String routeKey) { this.exchange = exchange; this.name = name; this.routeKey = routeKey; } }
package com.xx.xx.xx.config; import com.xx.xx.xx.xx.QueueEnum; import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 消息队列配置 * @author demo */ @Configuration public class RabbitMqConfig { /** * 订单消息实际消费队列所绑定的交换机 */ @Bean DirectExchange orderDirect() { return (DirectExchange) ExchangeBuilder .directExchange(QueueEnum.QUEUE_ORDER_CANCEL.getExchange()) .durable(true) .build(); } /** * 订单延迟队列队列所绑定的交换机 */ @Bean DirectExchange orderTtlDirect() { return (DirectExchange) ExchangeBuilder .directExchange(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getExchange()) .durable(true) .build(); } /** * 订单实际消费队列 */ @Bean public Queue orderQueue() { return new Queue(QueueEnum.QUEUE_ORDER_CANCEL.getName()); } /** * 订单延迟队列(死信队列) */ @Bean public Queue orderTtlQueue() { return QueueBuilder .durable(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getName()) .withArgument("x-dead-letter-exchange", QueueEnum.QUEUE_ORDER_CANCEL.getExchange())//到期后转发的交换机 .withArgument("x-dead-letter-routing-key", QueueEnum.QUEUE_ORDER_CANCEL.getRouteKey())//到期后转发的路由键 .build(); } /** * 将订单队列绑定到交换机 */ @Bean Binding orderBinding(DirectExchange orderDirect,Queue orderQueue){ return BindingBuilder .bind(orderQueue) .to(orderDirect) .with(QueueEnum.QUEUE_ORDER_CANCEL.getRouteKey()); } /** * 将订单延迟队列绑定到交换机 */ @Bean Binding orderTtlBinding(DirectExchange orderTtlDirect,Queue orderTtlQueue){ return BindingBuilder .bind(orderTtlQueue) .to(orderTtlDirect) .with(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getRouteKey()); } }
package com.xx.xx.xx.component; import com.xx.xx.xx.enume.QueueEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.AmqpException; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessagePostProcessor; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * 取消订单消息的发出者 * @author demo */ @Component @Slf4j public class CancelOrderSender { @Resource private AmqpTemplate amqpTemplate; public void sendMessage(String orderId,final long delayTimes){ //给延迟队列发送消息 amqpTemplate.convertAndSend(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getExchange(), QueueEnum.QUEUE_TTL_ORDER_CANCEL.getRouteKey(), orderId, new MessagePostProcessor() { @Override public Message postProcessMessage(Message message) throws AmqpException { //给消息设置延迟毫秒值 message.getMessageProperties().setExpiration(String.valueOf(delayTimes)); return message; } }); log.info("send delay message orderId:{}",orderId); } }
package com.xx.xx.xx.component; import com.xx.xx.main.service.DemoService; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.rabbit.annotation.RabbitHandler; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * 取消订单消息的处理者 * @author demo */ @Slf4j @Component @RabbitListener(queues = "demo.order.cancel") public class CancelOrderReceiver { @Resource private DemoService demoService; @RabbitHandler public void handle(String orderId){ try { demoService.cancelOverTimeOrder(orderId); } catch (BusinessException e) { log.info("receive delay message orderId:{},Exception:{}", orderId, e); } } }
package com.xx.xx.main.DemoService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; /** * @author abm */ @Slf4j @Service public class DemoServiceImpl implements DemoService{ @Override public CommonResult generateOrder(OrderParam orderParam) { //todo 执行一系类下单操作 LOGGER.info("process generateOrder"); //下单完成后开启一个延迟消息,用于当用户没有付款时取消订单(orderId应该在下单后生成) sendDelayMessageCancelOrder(orderId); return CommonResult.success(null, "下单成功"); } @Override public void cancelOverTimeOrder(String orderId) { //todo 执行一系类取消订单操作 LOGGER.info("process cancelOrder orderId:{}",orderId); } private void sendDelayMessageCancelOrder(String orderId) { //获取订单超时时间,假设为60分钟 long delayTimes = 30 * 1000; //发送延迟消息 cancelOrderSender.sendMessage(orderId, delayTimes); } }
觉得还可以的话可以的话点个赞呗
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。