天天跟我做,每天十分钟

  • 前言(〃・ิ‿・ิ)ゞ
  • 踩坑坑 (☄ฺ◣ω◢)☄ฺ
  • 爬坑坑 ( ⁼̴̀ .̫ ⁼̴́ )✧
  • 搞事事(ˊo̴̶̷̤ ᴗ o̴̶̷̤ˋ)
  • 大功告成₍˄·͈༝·͈˄₎ฅ˒˒


前言(〃・ิ‿・ิ)ゞ

最近在和订单打交道,其中关于过期这一块费了不少时间,分享出来给大家作为一种思路。

踩坑坑 (☄ฺ◣ω◢)☄ฺ

下单、支付、取消都很容易解决,但是最后竟然漏了最重要的订单过期!


根据公司业务的不同,订单过期涉及到返还库存or解锁冻结金额

最初的想法是写一个定时器去数据库轮询所有状态是未付款的订单,就类似于下面的亚子

/**
     * 每分钟查询一次数据库未付款的订单
     */
    @Scheduled(fixedDelay = 60000)
    public void query_order() {
        //外币八部  业务逻辑
    }

但是!刚写完就发现了问题!(( ◞•̀д•́)◞⚔◟(•̀д•́◟ ))

在数据量大的时候轮询数据库是及其耗费时间的!

并且如果订单在这一分钟之内过期了,库存并没有及时的返回,在限时秒杀这种业务场景下是极其恐怖的,友商可能重复下一些无效订单导致真实用户购买不到商品


转换一下思路,订单过期的时候不是我去找订单,而是订单主动来找我

爬坑坑 ( ⁼̴̀ .̫ ⁼̴́ )✧

订单是存在数据库的,数据库不可能主动来找我,这里提供两种方案:
一、
        通过消息队列(RabbitMQ、RocketMQ)延迟队列来解决,发送消息的时候设置一个消费(过期)时间,到了过期时间消费者自动获取这条消息来进行业务处理。
二、
        通过Redis来进行订单过期时间记录,下订单的时候给Key设置一个过期时间,系统监听过期的Key就可以了,我们这里就用第二种实现方式

搞事事(ˊo̴̶̷̤ ᴗ o̴̶̷̤ˋ)

首先配置一下Redis监听容器

@Configuration
public class RedisConfiguration {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    /**
     * 初始化Redis监听容器
     * @return
     */
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer() {
        RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
        redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
        return redisMessageListenerContainer;
    }

    /**
     * 创建一个Key监听器并且绑定到容器中
     * @return
     */
    @Bean
    public KeyExpiredListener keyExpiredListener() {
        return new KeyExpiredListener(this.redisMessageListenerContainer());
    }
 
}

之后创建一个类继承KeyExpirationEventMessageListener并重写onMessage方法

public class KeyExpiredListener extends KeyExpirationEventMessageListener {
 
    public KeyExpiredListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    /**
     * 监听所有失效的Key
     * @param message Key
     * @param pattern 不知道是个什么东东 父类也没有使用这个参数
     */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        System.out.println("过期的Key:" + message.toString());
    }
    
}

大功告成₍˄·͈༝·͈˄₎ฅ˒˒

去Redis设置一个临时Key测试一下监听器是否正常

java 优惠券算法 java优惠券过期_java


java 优惠券算法 java优惠券过期_java_02


这里就大功告成了づ♡ど

但是有一个注意事项:

监听到的Key得不到里面的值,所以一般把数据放在Key上,例如订单号

然后我们根据这个订单号进行库存、金额的操作就非常及时了,性能也很不错’◡’

java 优惠券算法 java优惠券过期_redis_03