基于RabbitMQ订单未支付30分钟自动取消
原创
©著作权归作者所有:来自51CTO博客作者gblfy的原创作品,请联系作者获取转载授权,否则将追究法律责任
文章目录
一、原理实现
1. 超时消费流程图
2. 死信队列的架构原理
相同点:
死信队列和普通队列区别不是很大
普通队列与死信队列都有自己的独立的交换机和路由key、队列和消费者。
不同点:
1.生产者投递消息先投递到我们普通交换机中,普通交换机再将该消息根据路由规则将消息路由到普通队列缓存起来,普通队列对应有自己独立的普通消费者。
2.如果生产者投递消息到普通队列中,普通队列发现该消息一致没有被消费者消费的情况下(设置过期时间),在这时候或将该消息转移到死信(备胎)交换机中,死信(备胎)交换机对应有自己独立的死信(备胎)队里,而死信(备胎)队列有对应的死信(备胎)消费者。
3. 订单超时30分钟实现原理
1.用户下单之后,投递一个msg消息存放在msg服务器daunt,该消息msg消息过期时间为30分钟,一致未被订单消费者消费,消息会转移到死信交换机路由到死信队列中,被我们的死信消费者30分钟后消息。
2.死信消费者在根据订单号码查询支付订单状态,如果是未支付情况下,则将该订单设置未超时。
对筛选出来的订单号码进行核对校验
- 1.订单中是否存在
- 2>携带订单号码调用支付宝查询订单支付状态是否为待支付
- 3>更新该订单号码状态
二、核心代码实战
2.1. 记录订单待支付数据
/**
* 订单会调用改接口提前将用户下单的金额、订单号码 传递到支付 提前存储到支付信息表中状态为待支付状态
*
* @param payOrderTokenDto
* @return
*/
@Override
public BaseResponse<String> toPayResultToken(PayOrderTokenDto payOrderTokenDto) {
//1.验证参数代码略
//2.将该数据插入到支付信息表中
PaymentInfoEntity paymentChannelEntity = dtoToDo(payOrderTokenDto, PaymentInfoEntity.class);
int result = paymentInfoMapper.insert(paymentChannelEntity);
if (result <= 0) {
return setResultError("插入支付记录失败!");
}
// 生成token令牌
Long id = paymentChannelEntity.getId();
//3.生成支付token令牌给vue
String payToken = tokenUtils.createToken(id + "");
// 向mq投递一条msg消息 设置过期时间 30分钟
orderTimeoutManage.sendOrderTimeoutMsg(id + "");
return setResultSuccess(payToken);
}
2.2. 超时消费者监听
@Component
public class PayOrderTimeoutConsumer {
@Autowired
private PayOrderTimeoutService payOrderTimeoutService;
/**
* 死信队列监听队列回调的方法
*
* @param msg
*/
@RabbitListener(queues = "mayikt_order_dlx_queue")
public void orderConsumer(String msg) {
Long payId = Long.parseLong(msg);
payOrderTimeoutService.orderTimeout(payId);
}
}
2.3. 订单核对校验
@Service
public class PayOrderTimeoutService {
@Autowired
private PaymentInfoMapper paymentInfoMapper;
public boolean orderTimeout(Long payId) {
// 消费者获取 支付的id 消费者如何消费 批量获取msg、多个消费者 、查询db 查询n个未支付状态id
// 1.根据该支付id 查询支付订单信息 状态 异步回调中如果用户支付成功了,从rabbitmq 将该消息删除 清理过期key
PaymentInfoEntity paymentInfoEntity = paymentInfoMapper.selectById(payId);
if (paymentInfoEntity == null) {
return false;
}
// 2.如果支付状态是为未支付的话,则将该状态该已超时
if (!PaymentConstant.PAYMENT_STATUS_NOT.equals(paymentInfoEntity.getPaymentStatus())) {
return false;
}
// 3. 主动调用下 支付宝接口 根据 订单状态查询 支付宝这边是否已经支付了---31 32分钟 调用支付宝接口查询
// 用户跳转到支付页面支付超时30分钟
// 3.调用库存接口 增加库存(33) 修改该状态为超时
paymentInfoEntity.setPaymentStatus(PaymentConstant.PAYMENT_STATUS_TIMEOUT);
paymentInfoMapper.updateById(paymentInfoEntity);
// 调用库存接口 新增库存
return true;
}
}