需求:

处理订单过期自动取消,比如下单30分钟未支付自动更改订单状态

用户绑定隐私号码当订单结束取消绑定等

解决方案1:

可以利用redis自带的key自动过期机制,下单时将订单id写入redis,过期时间30分钟,30分钟后检查订单状态,如果未支付,则进行处理但是key过期了redis有通知吗?答案是肯定的。

开启redis key过期提醒

修改redis相关事件配置。找到redis配置文件redis.conf,只需修改配置文件redis.conf中的:notify-keyspace-events Ex,默认为notify-keyspace-events "", 查看“notify-keyspace-events”的配置项,如果没有,添加“notify-keyspace-events Ex”,如果有值,添加Ex,相关参数说明如下:

K:keyspace事件,事件以__keyspace@<db>__为前缀进行发布;
E:keyevent事件,事件以__keyevent@<db>__为前缀进行发布;
g:一般性的,非特定类型的命令,比如del,expire,rename等;
$:字符串特定命令;
l:列表特定命令;
s:集合特定命令;
h:哈希特定命令;
z:有序集合特定命令;
x:过期事件,当某个键过期并删除时会产生该事件;
e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件;
A:g$lshzxe的别名,因此”AKE”意味着所有事件。
Redis测试:

打开一个redis-cli ,监控db0的key过期事件

打开另一个redis-cli ,发送定时过期key

观察上一个redis-cli ,会发现收到了过期的key hello,但是无法收到过期的value world

根据这个特性在springboot中使用

1.pom 中添加依赖

  <!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.定义配置RedisListenerConfig

/**
* @author mazhq
* @Title: RedisListenerConfig
* @ProjectName: zeus
* @date 2019/2/20 11:25
*/
@Configuration
public class RedisListenerConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) { RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
//container.addMessageListener(new RedisExpiredListener(), new PatternTopic("__keyevent@0__:expired"));
return container;
}
}
  • 3.定义监听器,实现KeyExpirationEventMessageListener接口,查看源码发现,该接口监听所有db的过期事件keyevent@*:expired"
/**
* @author mazhq
* @Title: RedisKeyExpirationListener
* @ProjectName: zeus
* @date 2019/2/20 11:26
*/
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
private final static Logger logger = LoggerFactory.getLogger(RedisKeyExpirationListener.class);
@Autowired
private RedisClient redisClient;
/**
* Creates new {@link MessageListener} for {@code __keyevent@*__:expired} messages.
*
* @param listenerContainer must not be {@literal null}.
*/
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
} @Override
public void onMessage(Message message, byte[] pattern) {
// 用户做自己的业务处理即可,注意message.toString()可以获取失效的key
String expiredKey = message.toString();
if(expiredKey.startsWith("zeus:order")){
//TODO
}
}
}

  

或者打开RedisListenerConfigcontainer.addMessageListener(new RedisExpiredListener(), new PatternTopic("__keyevent@0__:expired")); 注释,再定义监听器,监控__keyevent@0__:expired事件,即db0过期事件。这个地方定义的比较灵活,可以自己定义监控什么事件。

public class RedisExpiredListener implements MessageListener {

    /**
* 客户端监听订阅的topic,当有消息的时候,会触发该方法;
* 并不能得到value, 只能得到key。
* 姑且理解为: redis服务在key失效时(或失效后)通知到java服务某个key失效了, 那么在java中不可能得到这个redis-key对应的redis-value。
* * 解决方案:
* 创建copy/shadow key, 例如 set vkey "vergilyn"; 对应copykey: set copykey:vkey "" ex 10;
* 真正的key是"vkey"(业务中使用), 失效触发key是"copykey:vkey"(其value为空字符为了减少内存空间消耗)。
* 当"copykey:vkey"触发失效时, 从"vkey"得到失效时的值, 并在逻辑处理完后"del vkey"
*
* 缺陷:
* 1: 存在多余的key; (copykey/shadowkey)
* 2: 不严谨, 假设copykey在 12:00:00失效, 通知在12:10:00收到, 这间隔的10min内程序修改了key, 得到的并不是 失效时的value.
* (第1点影响不大; 第2点貌似redis本身的Pub/Sub就不是严谨的, 失效后还存在value的修改, 应该在设计/逻辑上杜绝)
* 当"copykey:vkey"触发失效时, 从"vkey"得到失效时的值, 并在逻辑处理完后"del vkey"
*
*/
@Override
public void onMessage(Message message, byte[] bytes) {
byte[] body = message.getBody();// 建议使用: valueSerializer
byte[] channel = message.getChannel();
System.out.print("onMessage >> " );
System.out.println(String.format("channel: %s, body: %s, bytes: %s"
,new String(channel), new String(body), new String(bytes)));
} }

解决方案2

使用spring + quartz定时任务(支持任务信息写入mysql,多节点分布式执行任务),下单成功后,生成一个30分钟后运行的任务,30分钟后检查订单状态,如果未支付,则进行处理

解决方案3

将订单过期时间信息写入mysql,按分钟轮询查询mysql,如果超时则进行处理,效率差!时间精准度底!

结论

推荐使用方案1和方案2

Spring boot实现监听Redis key失效事件实现和其它方式的更多相关文章

  1. 【Redis系列】Spring boot实现监听Redis key失效事件

    talk is cheap, show me the code. 一.开启Redis key过期提醒 方式二:修改配置文件 redis.conf # 默认 notify-keyspace-events ...

  2. SpringBoot实现监听redis key失效事件

    需求: 处理订单过期自动取消,比如下单30分钟未支付自动更改订单状态 解决方案1: 可以利用redis天然的key自动过期机制,下单时将订单id写入redis,过期时间30分钟,30分钟后检查订单状态 ...

  3. 订单超时、活动过期解决方案:php监听redis key失效触发回调事件

    Redis 的 2.8.0 版本之后可用,键空间消息(Redis Keyspace Notifications),配合 2.0.0 版本之后的 SUBSCRIBE 就能完成这个定时任务的操作了,定时的 ...

  4. Node.js 中监听 redis key 过期事件

    It is in fact possible to listen to the “expired” type keyevent notification using a subscribed clie ...

  5. springboot redis 监听过期key值事件

    redis 中的key值过期后,触发通知事件 1.创建springboot工程,创建监听类 maven配置 <dependencies> <dependency> <gr ...

  6. springboot使用Redis,监听Redis键过期的事件设置与使用代码

    我使用的是Windows下的Redis服务,所以一下Redis设置都是在Windows平台进行. 1.修改Redis配置文件 1.1:Windows下的Redis存在两个配置文件 修改带有servic ...

  7. Spring Boot 2.x整合Redis

    最近在学习Spring Boot 2.x整合Redis,在这里和大家分享一下,希望对大家有帮助. Redis是什么 Redis 是开源免费高性能的key-value数据库.有以下的优势(源于Redis ...

  8. Spring boot配置多个Redis数据源操作实例

    原文:https://www.jianshu.com/p/c79b65b253fa Spring boot配置多个Redis数据源操作实例 在SpringBoot是项目中整合了两个Redis的操作实例 ...

  9. 7、Spring Boot 2.x 集成 Redis

    1.7 Spring Boot 2.x 集成 Redis 简介 继续上篇的MyBatis操作,详细介绍在Spring Boot中使用RedisCacheManager作为缓存管理器,集成业务于一体. ...

随机推荐

  1. 集合框架—常用的map集合

    1.Collections.synchronizedMap() 实现上在调用map所有方法时,都对整个map进行同步,而ConcurrentHashMap的实现却更加精细,它对map中的所有桶加了锁. ...

  2. Linux基础命令---mkisofs

    mkisofs mkisofs指令可以创建ISO9660/Joliet/HFS文件系统,现在使用指令genisoimage代替它.genisoImage是一个预掌握程序,用于生成iso 9660/jo ...

  3. bzoj3524 [Poi2014]Couriers/2223 [Coci 2009]PATULJCI

    题目链接1 题目链接2 主席树模板题 两题有细节不同 #include<algorithm> #include<iostream> #include<cstdlib> ...

  4. [转载]论asp.net out、ref、return

      论asp.net out.ref.return ref(引用类型) ref引用类型进出都必须赋值,赋值后会改变类型原来的指针.   out(值类型) out值类型进可以不赋值,出必须赋值.   r ...

  5. 手撕vue-cli配置——webpack.base.conf.js篇

    在开始写webpack.base.conf.js(简称base)之前,我们先来看一下vue-loader.conf.js这个文件,毕竟在base中我们还会用到: 'use strict' //引入前一 ...

  6. java反射field和method的顺序问题

    最近在有思考到序列化性能优化的问题,关于java反射field和method的顺序问题,这里有详细的讨论http://stackoverflow.com/questions/5001172/java- ...

  7. 20145318《网络对抗》Web安全基础实践

    20145318<网络对抗>Web安全基础实践 基础问题回答 1.SQL注入原理,如何防御 SQL注入 就是通过把SQL命令插入到“Web表单递交”或“输入域名”或“页面请求”的查询字符串 ...

  8. 【转】iOS学习之iOS禁止Touch事件

    iOS程序中有时会有需要禁止应用接收Touch的要求(比如动画进行时,防止触摸事件触发新方法). 一.一般有两种: 1.弄个遮罩层,禁止交互: 2.使用UIApplication中的方法进行相关的交互 ...

  9. CRT中的时间(time_t和tm)(转载)

    转载:http://blog.csdn.net/bokee/article/details/5330682 首先介绍基本的时间概念. 时间一般分为两种,一种是本地时间(Local Time),一种是协 ...

  10. strerror函数的总结

    定义函数:char * strerror(int errnum); 函数说明:strerror()用来依参数errnum 的错误代码来查询其错误原因的描述字符串, 然后将该字符串指针返回. 返回值:返 ...