文章目录
- 一、原理实现
- 1. 超时消费流程图
- 2. 订单超时30分钟实现原理
- 二、核心代码实战
- 2.1. 记录订单待支付数据
- 2.2. redis配置
- 2.3. 超时消费者监听
一、原理实现
1. 超时消费流程图
2. 订单超时30分钟实现原理
①用户下单之后,投递一个订单号码存放到redis服务端,该订单号码过期时间为30分钟
②redis客户端监听redis服务端指定数据库的将过期的订单号码key,对将过期的订单号码进行筛选。
③对筛选出来的订单号码进行核对校验
- 1.订单中是否存在
- 2>携带订单号码调用支付宝查询订单支付状态是否为待支付
- 3>更新该订单号码状态
二、核心代码实战
2.1. 记录订单待支付数据
/*** 订单会调用改接口提前将用户下单的金额、订单号码 传递到支付 提前存储到支付信息表中状态为待支付状态** @param payOrderTokenDto* @return*/@Overridepublic 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令牌给vueString payToken = tokenUtils.createToken(id + "");// 向mq投递一条msg消息 设置过期时间 30分钟、// TODO 将订单号码存储到redis中并设置过期时间为30分钟return setResultSuccess(payToken);}
2.2. redis配置
@Configuration
public class RedisConfig {@BeanRedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);//redis之监听database0 库的将要过期keycontainer.addMessageListener(new RedisKeyExpirationListener(container), new PatternTopic("__keyevent@0__:expired"));return container;}
}
2.3. 超时消费者监听
@Component
@Slf4j
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {@Autowiredprivate PayOrderTimeoutService payOrderTimeoutService;public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {super(listenerContainer);}/*** 针对 redis 数据失效事件,进行数据处理** @param message* @param pattern*/@Overridepublic void onMessage(Message message, byte[] pattern) {// redis 客户端监听 Redis 16库 每个库对应不同的业务逻辑 前缀 order_timeOut_支付idString key = message.toString();if (key.contains("order_timeOut_")) {String keyDeal = key.replace("order_timeOut_", "");log.info(">keyDeal:{}已经过期!<", keyDeal);Long payId = Long.parseLong(keyDeal);payOrderTimeoutService.orderTimeout(payId);}}
}
@Service
public class PayOrderTimeoutService {@Autowiredprivate PaymentInfoMapper paymentInfoMapper;public boolean orderTimeout(Long payId) {// 消费者获取 支付的id 消费者如何消费 批量获取msg、多个消费者 、查询db 查询n个未支付状态id// 1.根据该支付id 查询支付订单信息 状态 异步回调中如果用户支付成功了,从rabbitmq 将该消息删除 清理过期keyPaymentInfoEntity 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;}
}
补充:不建议使用redis实现
请勿过度依赖Redis的过期监听
https://developer.aliyun.com/article/760276