转 https://blog.youkuaiyun.com/qq_26360877/article/details/106184296
需求分析:24小时内未支付的订单过期失效。
解决方案
- 被动设置:在查询订单的时候检查是否过期并设置过期状态。
- 定时调度:定时器定时查询并过期需要过期的订单。
- 延时队列:将未支付的订单放入一个延时队列中,依次取出过期订单。
- 过期提醒:reids支持将一个过期的key(订单号)通知给客户端,根据过期的订单号进行相应的处理。
被动设置:
就是在查询的时候判断是否失效,如果失效了就给他设置失效状态
定时调度:
利用一个定时器,在设置的周期内轮询检查并处理需要过期的订单。
具体实现有基于Timer
的,有基于Quartz
,还有springboot自带的Scheduler
缺点:
(1)不能够精准的去处理过期订单,轮询周期设置的越小,精准度越高,但是项目的压力越大,我们上一个项目就有这种状况,太多定时器在跑,项目运行起来比较笨重。
(2)而且需要处理的是过期的订单,但是要查询所有未支付的订单,范围大。对于大订单量的操作不合适。
@Schedule(cron="0/5 * * * * ?")
按顺序依次为
1 秒(0~59)
2 分钟(0~59)
3 小时(0~23)
4 天(0~31)
5 月(0~11)
6 星期(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT)
7.年份(1970-2099)eg1: 0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
eg2: 0 15 10 * * ? 2005 2005年的每天上午10:15触发
过期提醒:
基于redis的过期提醒功能;
1、修改redis配置开启“过期提醒”
notify-keyspace-events
改为notify-keyspace-events "Ex"
2、继承
KeyExpirationEventMessageListener ,重写onMessageimport org.springframework.data.redis.connection.Message; import org.springframework.data.redis.listener.KeyExpirationEventMessageListener; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.stereotype.Component; import java.util.Date; /** * @author mashu * Date 2020/5/17 23:01 */ @Component public class OrderExpirationListener extends KeyExpirationEventMessageListener { public OrderExpirationListener(RedisMessageListenerContainer listenerContainer) { super(listenerContainer); } @Override public void onMessage(Message message, byte[] pattern) { final String expiredKey = message.toString(); System.out.println("我过期了" + expiredKey+"当前时间:"+new Date()); } }
3、向redis中存入一个订单,过期时间为1分钟。
redis.set("orderCode/10010", "1", 1L, TimeUnit.MINUTES); System.out.println("redis存入订单号 key: orderCode/10010,value:1,过期时间一分钟,当前时间"+new Date());
4、运行