Redis自动过期机制之key的过期监听(7)

前言

比如我们需要监听那些key已经过期,再进行对该数据进行下一步的业务处理。
实现需求:处理订单过期自动取消,比如下单15分钟未支付自动更改订单状态
实现方案:
1.使用Redis Key自动过期出发事件通知
2.使用定时任务15分钟后检查
3.按照每分钟轮训检查

1.使用Redis Key自动过期机制

当我们的key失效时,我们可以执行我们的客户端回调监听的方法。
需要在redis中配置:notify-keyspace-events “Ex”
在这里插入图片描述

2.Springboot整合key过期监听

2.1. 创建表 order_number

CREATE TABLE `order_number` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `order_name` varchar(255) DEFAULT NULL,
  `order_status` int(11) DEFAULT NULL,
  `order_token` varchar(255) DEFAULT NULL,
  `order_id` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

2.2核心代码

列举部分核心监控redis失效key的代码,详见github项目 :springboot-redis【redis-listener】

2.2.1 核心代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

@Configuration
public class RedisListenerConfig {
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        return container;
    }
}
import com.redmaple.entity.OrderEntity;
import com.redmaple.mapper.OrderMapper;
import com.redmaple.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;

/**
 * @description:
 * @author: uwank171
 * @date: 2022/9/2 14:40
 */
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

    private final static String ORDER_ = "order_";

    @Autowired
    private OrderService orderService;

    /**
     * Creates new {@link MessageListener} for {@code __keyevent@*__:expired} messages.
     *
     * @param listenerContainer must not be {@literal null}.
     */
    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    /**
     * Redis失效事件 key
     * @param message
     * @param pattern
     */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        // 表示失效过期的key值
        String expiraKey = message.toString();
        System.out.println(">>>>> 过期的key: " + expiraKey);
        // 做业务处理 TODO
        if (expiraKey.startsWith(ORDER_)) {
            orderService.doOrderExpireKey(expiraKey);
        }
    }
}
import com.redmaple.entity.OrderEntity;
import com.redmaple.mapper.OrderMapper;
import com.redmaple.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @description:
 * @author: uwank171
 * @date: 2022/9/2 15:10
 */
@Service
public class OrderServiceImpl implements OrderService {
    /**
     * 待支付
     */
    private static final Integer ORDER_STAYPAY = 0;
    /**
     * 失效
     */
    private static final Integer ORDER_INVALID = 2;


    @Autowired
    private OrderMapper orderMapper;
    /**
     * 处理过期的key
     *
     * @param expiraKey
     */
    @Override
    public void doOrderExpireKey(String expiraKey) {
        // 根据key查询 value 如果还还是为待支付状态 将订单改为已经超时~~
        OrderEntity orderNumber = orderMapper.getOrderNumber(expiraKey);
        System.out.println(expiraKey);
        if (orderNumber == null) {
            return;
        }
        if (orderNumber.getOrderStatus().equals(ORDER_STAYPAY)) {
            // 将订单状态改为已经失效
            orderMapper.updateOrderStatus(expiraKey, ORDER_INVALID);
        }
        System.out.println(">>>>> doOrderExpireKey 完成");
    }
}
import com.redmaple.common.util.JedisUtil;
import com.redmaple.entity.OrderEntity;
import com.redmaple.mapper.OrderMapper;
import com.redmaple.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
public class OrderController {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderService orderService;

    @Autowired
    private JedisUtil jedisUtil;

    private final static String ORDER_ = "order_";

    @RequestMapping("/saveOrder")
    public String saveOrder() {
        // 1.生成token
        String orderToken = ORDER_ + UUID.randomUUID().toString();
        String orderId = System.currentTimeMillis() + "";
        //2. 将该token存放到redis中
        jedisUtil.set(orderToken, orderId);
        jedisUtil.expire(orderToken, 10);
        OrderEntity orderEntity = new OrderEntity(null, "C测试监听redis失效过期的key值", orderId, orderToken);
        int result = orderMapper.insertOrder(orderEntity);
        return result > 0 ? "success" : "fail";
    }
}
2.2.2 maven核心依赖
		<!-- SpringBoot-整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 集成lombok 框架 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!-- springboot-redis 和 jedis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- Jedis 客户端 -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>

        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.0</version>
        </dependency>

        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
2.2.3 application.yml
server:
  port: 7000

spring:
  redis:
    database: 0
    host: 172.28.13.140
    port: 7000
    password: China1234
    timeout: 10000
    jedis:
      pool:
        max-active: 500
        min-idle: 5
        max-idle: 50
        max-wait: 60000
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    ## 数据库
    url: jdbc:mysql://127.0.0.1:3306/gi_test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
    username: root
    password: root

如果该文章能够帮助到你,希望麻烦点赞收藏下,谢谢

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Redis集群中实现key过期监听机制有多种方式,以下是其中一种常用的方法: 1. 使用Redis的发布订阅功能:Redis的发布订阅功能可以用于实现key过期监听机制。具体步骤如下: - 客户端(订阅者)使用`SUBSCRIBE`命令订阅一个频道,例如`__keyevent@0__:expired`,其中`0`表示数据库编号。这个频道是Redis内置的用于监听key过期事件的频道。 - 当一个key过期时,Redis会将一个消息发布到该频道,消息的内容为过期key。 - 客户端(订阅者)通过监听该频道的消息来得知key过期的事件,进而执行相应的处理逻辑。 注意:由于Redis集群中的不同节点之间的消息传递是异步的,所以无法保证每个节点都能及时收到过期事件的消息。如果需要保证实时性,可以使用以下方法。 2. 使用Lua脚本和Lua脚本调用:Redis支持使用Lua脚本进行操作,结合Lua脚本调用可以实现集群中的key过期监听机制。具体步骤如下: - 编写一个Lua脚本,该脚本通过`KEYS`和`ARGV`参数接收过期key和其他参数。 - 使用Redis的`EVAL`命令调用Lua脚本,传递过期key和其他参数。 - 在Lua脚本中,可以执行相应的处理逻辑,比如将过期key添加到一个队列中,供其他程序消费。 - 其他程序可以通过消费队列中的过期key来得知key过期的事件,进而执行相应的处理逻辑。 注意:使用Lua脚本和Lua脚本调用可以保证在集群中的每个节点都能及时处理过期事件,但需要注意处理过期事件的逻辑不能太复杂,以免影响Redis的性能。 以上是Redis集群中实现key过期监听机制的两种常用方法,根据具体需求选择适合的方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值