利用redis天然的key自动过期机制,下单时将订单id写入redis,
过期时间30分钟,30分钟后检查订单状态,如果未支付,则进行处理。

开启redis key过期提醒

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

1
2
3
4
5
6
7
8
9
10
11
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过期事件

1
2
3
4
5
127.0.0.1:6379> PSUBSCRIBE __keyevent@0__:expired
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__keyevent@0__:expired"
3) (integer) 1

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

1
127.0.0.1:6379> setex test_key 3 test_value

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

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> PSUBSCRIBE __keyevent@0__:expired
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "__keyevent@0__:expired"
3) (integer) 1
1) "pmessage"
2) "__keyevent@0__:expired"
3) "__keyevent@0__:expired"
4) "test_key"

在springboot中使用

1.pom 中添加依赖

1
2
3
4
5
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.定义配置RedisListenerConfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

import com.example.wendy.controller.RedisKeyExpirationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

/**
* @Author: zy
* @Date: 2019/7/17 18:23
*/
@Configuration
@ComponentScan("com.example.wendy.controller")
public class RedisListenerConfig {

@Bean
RedisMessageListenerContainer listenerContainer(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer listenerContainer = new RedisMessageListenerContainer();
listenerContainer.setConnectionFactory(connectionFactory);
return listenerContainer;
}

@Bean
KeyExpirationEventMessageListener redisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
return new RedisKeyExpirationListener(listenerContainer);
}

}

3.定义监听器,实现KeyExpirationEventMessageListener接口,查看源码发现,该接口监听所有db的过期事件keyevent@*:expired”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

/**
* @Author: zy
* 监听所有db的过期事件__keyevent@*__:expired"
* @Date: 2019/7/17/0017 17:56
*/
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

private Logger logger = LoggerFactory.getLogger(this.getClass());


public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}

/**
* 针对redis数据失效事件,进行数据处理
*
* @param message
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {

// 获取失效数据的key
String expiredKey = message.toString();

System.out.println("弹出来啦。。。。: " + expiredKey);


}
}