一:业务场景
在实际场景中,会遇到生成订单过30分钟或15分钟取消等等业务。
第一种方法:数据库轮询 (消耗数据库性能)
第二种方法:基于JDK-DelayQueue实现的延迟队列(重启队列数据全消失)
第三种方法:使用定时任务隔断时间去查(浪费性能)
第三种方法:基于Redis-keyspaceNotification实现的过期事件
第四种方法:使用消息队列
二:实现思路
在生成订单时,向 Redis 中增加一个 KV 键值对,K 为订单号,保证通过 K 能定位到数据库中的某个订单即可,V 可为任意值。因为过期取消的键值对,只拿得到key,拿不到value。并且在支付成功时,回调接口修改状态可以把对应的key删掉。
三:代码实现
继承KeyExpirationEventMessageListener 类:监听,过期会回调
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
public void onMessage(Message message, byte[] bytes) {
//key过期监听
System.out.println("开始执行过期事件");
//获取过期的key
String expireKey = message.toString();
//赛事订单取消
if(expireKey.contains("apply:competitiong:")) {
expireKey = expireKey.replace("apply:competitiong:", "");
String orderId = expireKey;
sysCompetitionApplyService.doDelayQueue(Long.valueOf(orderId));
System.out.println("redis取消赛事订单");
}
//赛事定级取消
if(expireKey.contains("apply:rank:")) {
expireKey = expireKey.replace("apply:rank:", "");
String orderId = expireKey;
sysRankApplyService.doDelayQueueRank(Long.valueOf(orderId));
System.out.println("redis取消定级订单");
}
//信息打印
System.out.println("失效的key"+expireKey);
}
}
redis工具类
@Component
public class RedisService
{
@Autowired
public Redistemplate redistemplate;
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public <T> void setCacheObject(final String key, final T value)
{
redistemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit)
{
redistemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout)
{
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit)
{
return redistemplate.expire(key, timeout, unit);
}
}
业务实现
// 设置15分钟取消订单
String redisKey = String.valueOf(StrUtil.format("{}{}",
"apply:competitiong:", sysCompetitionApply.getApplyId()));
redisService.setCacheObject
(redisKey,sysCompetitionApply.getApplyId() ,15L, TimeUnit.MINUTES);
// 设置15分钟取消订单 ,key随便设置
String redisKey = String.valueOf(StrUtil.format("{}{}",
"apply:rank:", sysRankApply.getApplyId()));
redisService.setCacheObject
(redisKey,sysRankApply.getApplyId() , 15L, TimeUnit.MINUTES);
TimeUnit.DAYS 日
TimeUnit.HOURS 时
TimeUnit.MINUTES 分
TimeUnit.SECONDS 秒
TimeUnit.MILLISECONDS 毫秒
原文地址:https://www.jb51.cc/wenti/3287373.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。