1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 商品下单未支付 如何取消订单?

商品下单未支付 如何取消订单?

时间:2023-07-10 06:51:37

相关推荐

商品下单未支付 如何取消订单?

一、业务场景

当下完订单,一般超过15分钟或者30分钟就需要对未支付的订单进行关闭。

二、解决方案
1.定时任务

通过定时任务隔一段时间扫描一次的数据,超过时间的订单,修改为取消状态

public class OrderCloseTask {@Scheduled(cron = "0 0/15 * * * ?")public void closeOrder() {// .. 关闭订单}}

问题:

时效性差

定时任务每15分钟扫一次,如果14:59创建了的单子,那关闭订单的时候就滞后了性能差

每隔一段时间就要扫描一次表数据,扫描表操作数据的时候,可能会加锁,性能比较低

2.redis pub/sub 发布订阅

下单,在redis创建一个带失效时间的key。通过key失效,监听key失效的事件,去取消订单

package com.xiaokk.house.web.config;import lombok.extern.slf4j.Slf4j;import org.springframework.data.redis.connection.Message;import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;import org.springframework.data.redis.listener.RedisMessageListenerContainer;import java.nio.charset.StandardCharsets;/*** 功能:** @author kangping* @date -01-29 1:20 下午*/@Slf4jpackage com.xiaokk.house.web.config;import lombok.extern.slf4j.Slf4j;import org.springframework.data.redis.connection.Message;import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;import org.springframework.data.redis.listener.RedisMessageListenerContainer;import java.nio.charset.StandardCharsets;/*** 功能:** @author kangping* @date -01-29 1:20 下午*/@Slf4jpublic class KeyExpiredListener extends KeyExpirationEventMessageListener {/*** Creates new {@link MessageListener} for {@code __keyevent@*__:expired} messages.** @param listenerContainer must not be {@literal null}.*/public KeyExpiredListener(RedisMessageListenerContainer listenerContainer) {super(listenerContainer);}@Overridepublic void onMessage(Message message, byte[] pattern) {// 失效的keyString key = new String(message.getBody(), StandardCharsets.UTF_8);log.info("key = {}", key);// 消息来自于那个渠道,redis默认有16个库,就有16个渠道String channel = new String(message.getChannel(), StandardCharsets.UTF_8);log.info("channel = {}", channel);// 监听的渠道 "__keyevent@*__:expired 默认兼容所有的数据库String patt = new String(pattern, StandardCharsets.UTF_8);log.info("patt = {}",patt);// 取消订单}}

创建消息监听的一个容器

@Beanpublic RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory) {RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);return redisMessageListenerContainer;}@Beanpublic KeyExpiredListener keyExpiredListener(RedisMessageListenerContainer redisMessageListenerContainer) {return new KeyExpiredListener(redisMessageListenerContainer);}

问题

发布到所有的订阅者

一般订单服务会有多个,假如订单服务有3个,那3个都会去取消订单。如果想到加入分布式锁,如果抢到锁的服务挂了。取消订单就是失败了。就没有了可靠性性能问题

keyevent@*:expired 默认是监听的所有渠道,代表不是订单取消相关的key也会进入到这个监听方法。时效性

redis 的key 是维护在一个字典表当中,redis是每1秒去检查几次这些key,每次检查中是抽取一定的比例的key,看这些key是否已经失效。如果key比较多,可能就有个别的key总是没有被抽取到,导致key没有及时失效。在抽取的key当中,如果超过一定量的比例都失效,redis会减少去检查的时间,导致检查得更加频繁。而woker本身是单线程,所有有性能损耗。

3.延时消息

创建订单的时候发送一个延时消息。消费的时候判断订单是否还是待支付状态,如果是,则关闭订单

优点

正常情况下,只有一个订单服务会去消费消息ask机制可以保证,至少消费一次。保证了可靠性

缺点

发送消息可能是有网络延时的,或者mq队列中消息很多,时间到了还没有被消费到。还是会有实时性问题。

解决方案:

通过业务方式去处理,在支付的时候去判断这个订单是否是已经过期,如果已经过期,在取消订单

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。