0
点赞
收藏
分享

微信扫一扫

基于Spring Boot实现Redis Key过期失效处理

菜菜捞捞 2021-09-29 阅读 56

1 场景描述

用户下单,默认保留 15分钟 的支付时间,在规定的时间内用户未完成支付即设置订单状态为 已取消

2 前言

不管你用没用过 redis,它有一个功能你一定会觉得很奈斯,那就是 key 的过期失效机制,请看 Redis官方解释,简单来讲就是 key 超时过期后会自动删除。这里我们就使用 redis 来实现上面描述的这种场景!

3 环境

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 实现了这个功能。
当然实现这个功能不止这一种方法,各位朋友可以尽显神通!

举报

相关推荐

0 条评论