SpringBoot集成Redis过期时间监听事件失效

一、问题背景

前几天,在给公司测试环境部署新项目时,出现了一个问题。有一个“订单三十分钟未支付自动取消”的业务,用到了Redis的过期时间监听事件的技术。但是项目成功启动,创建完订单时,过了三十分钟,订单却迟迟没有取消。我们的开发人员在监听事件代码中打log,也一直没有看到日志。浏览了一些文章,终于解决了这个问题,做一下记录。

二、代码示例

1、创建订单接口

Controller

@RestController
@RequestMapping("/api/order")
@Api(tags = "订单相关")
public class OrderController {

    @Resource
    private OrderService orderService;

    @PostMapping("/create")
    @ApiOperation(value = "创建订单")
    public ResponseEntity<Void> createOrder(@RequestBody CreateOrderRequest request) {
		orderService.createOrderService(request)
        return ResponseEntity.ok().build();
    }

}

Service

@Transactional
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

		// 创建订单
    public void createOrderService(CreateOrderRequest request) {
        // 校验入参是否正确

        // 判断用户是否存在,状态是否正常

        // 生成订单记录
        Order order = new Order();
        // 初始化订单状态;1待付款;2已付款;3已取消
        order.setOrderStatus(1);
        boolean flag = this.save(order);

        // 订单创建成功后,将订单ID存入Redis,并设置过期时间为5分钟
        if (flag) {
            String redisKey = "order:" + order.getId();
            redisTemplate.opsForValue().set(redisKey, order.getId(), 30, TimeUnit.MINUTES);
        }
    }

}

2、监听事件

@Component
public class OrderMonitorListener extends KeyExpirationEventMessageListener {

    @Resource
    private OrderMapper orderMapper;

    public OrderMonitorListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
        setKeyspaceNotificationsConfigParameter(null);
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        String msg = message.toString();
        if (msg.contains("order:")) {
            String[] msgArray = msg.split(":");
            //查询订单
            String orderId = msgArray[1];
            Order order = orderMapper.selectById(orderId);
            if (ObjectUtils.isEmpty(order)) {
                throw new RuntimeException("订单不存在或已被删除");
            }
            //存在则修改订单状态为已取消
            order.setOrderStatus(3);
            orderMapper.updateById(order);
        }
    }

}

3、支付接口

支付接口代码不作展示,记得把创建订单时创建的RedisKey删除即可。

三、解决问题

  1. 问题根源,Redis配置文件中的过期时间通知未开启;
  2. 打开Redis配置文件,最后一行加上“notify-keyspace-events Ex”;
  3. 重启Redis即可。
docker restart redis

四、配置文件展示

protected-mode no
port 6379
timeout 0
save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump.rdb
dir /data
appendonly yes
appendfsync everysec
requirepass 123456
notify-keyspace-events Ex

notify-keyspace-events 的参数为:

字符发送的通知
K键空间通知,所有通知以 keyspace@ 为前缀
E键事件通知,所有通知以 keyevent@ 为前缀
gDEL 、 EXPIRE 、 RENAME 等类型无关的通用命令的通知
$字符串命令的通知
l列表命令的通知
s集合命令的通知
h哈希命令的通知
z有序集合命令的通知
x过期事件:每当有过期键被删除时发送
e驱逐(evict)事件:每当有键因为 maxmemory 政策而被删除时发送
A参数 g$lshzxe 的别名

看一下配置项和代码,我们就能明白,这个过期时间监听事件的原理,也是Redis那边做所有Key的轮询,然后将到过期时间的Key通过消息的方式,发送到服务端,服务端接收到消息之后,做业务的处理;这么一想,其实跟消息队列MQ没啥区别,这也是Redis能实现MQ功能的原因。

所有你想象的一切,皆是现实!
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot中,可以使用Spring Data Redis监听Redis中的键过期事件。具体操作如下: 1. 添加依赖 在pom.xml文件中添加spring-boot-starter-data-redisspring-boot-starter-web依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 2. 配置RedisTemplate 在application.properties或application.yml文件中配置Redis连接信息和RedisTemplate: ```yaml spring: redis: host: localhost port: 6379 database: 0 password: 123456 timeout: 10000 cache: type: redis ``` ```java @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } } ``` 3. 配置消息监听器 创建一个Redis过期事件监听器,实现MessageListener接口,重写onMessage方法: ```java @Component public class RedisKeyExpirationListener implements MessageListener { @Override public void onMessage(Message message, byte[] pattern) { String expiredKey = message.toString(); // 在这里实现过期时的处理逻辑 System.out.println("Key expired: " + expiredKey); } } ``` 4. 配置监听器容器 在配置类中创建一个RedisMessageListenerContainer对象,设置RedisConnectionFactory、MessageListenerAdapter和监听的Pattern: ```java @Configuration public class RedisConfig { @Autowired private RedisKeyExpirationListener redisKeyExpirationListener; @Bean public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory factory) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(factory); container.addMessageListener(new MessageListenerAdapter(redisKeyExpirationListener), new PatternTopic("__keyevent@0__:expired")); return container; } } ``` 以上就是配置Redis过期监听的步骤,监听器容器启动后,就可以监听Redis中键的过期事件了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值