1 场景描述
用户下单,默认保留 15分钟
的支付时间,在规定的时间内用户未完成支付即设置订单状态为 已取消
。
2 前言
不管你用没用过 redis,它有一个功能你一定会觉得很奈斯,那就是 key 的过期失效机制,请看 Redis官方解释,简单来讲就是 key 超时过期后会自动删除。这里我们就使用 redis 来实现上面描述的这种场景!
3 环境
JDK 1.8
Spring Boot 2.1.6
4 代码实现
4.1 项目创建
- 创建 Spring Initializer 项目
- 添加依赖
spring-boot-starter-data-redis
(主要依赖)
spring-boot-starter-web
(只为后面编写接口做辅助)
lombok
(只为减少代码量)
完整依赖:
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
- 配置 application.yml
spring:
redis:
host: 127.0.0.1
port: 6379
4.2 redis监听器容器配置类
@Configuration
public class RedisListenerConfig {
@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
}
4.3 key 过期监听器
@Component
@Slf4j
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
public void onMessage(Message message, byte[] pattern) {
// 注意:我们只能获取到失效的 key 而获取不到 value,
// 所以在设计 key 的时候可以考虑把 value 一并放到 key,然后根据规则取出 value
String key = new String(message.getBody());
log.info("key:{}", key);
// message.toString()也可以获取失效的key
String expiredKey = message.toString();
log.info("expiredKey:{}", expiredKey);
//如果是 order- 开头的key,将订单状态设置为 已取消
if(expiredKey.startsWith("order-")){
log.info("订单已过期:查询数据库对应记录是否已支付");
// TODO
}
}
}
4.4 测试
- 编写接口测试
@RestController
public class WebController {
@Autowired
private StringRedisTemplate redisTemplate;
@PostMapping("/order")
public String order() {
// 订单号
String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
// 假设 redis key 设置过期时间:30s
redisTemplate.opsForValue().set(String.format("order-%s", orderNo),
orderNo, 30, TimeUnit.SECONDS);
return orderNo;
}
}
启动项目,请求接口测试,控制台打印日志:
key:order-5b84dacd0a014dbbaa97cf26852f715b
expiredKey:order-5b84dacd0a014dbbaa97cf26852f715b
订单已过期:查询数据库对应记录是否已支付
如上所述,我们利用 redis 实现了这个功能。
当然实现这个功能不止这一种方法,各位朋友可以尽显神通!
2019-07-29更新
更新的原因很简单:多写了一点内容,所以删除了,免得误导他人!
网友评论