• Redis自动过期机制之key的过期监听


    前言

    比如我们需要监听那些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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    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);
            }
        }
    }
    
    • 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
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    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 完成");
        }
    }
    
    • 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
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    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";
        }
    }
    
    • 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
    2.2.2 maven核心依赖
    		
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
            
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
            dependency>
    
            
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-data-redisartifactId>
            dependency>
            
            <dependency>
                <groupId>redis.clientsgroupId>
                <artifactId>jedisartifactId>
            dependency>
    
            <dependency>
                <groupId>org.apache.commonsgroupId>
                <artifactId>commons-lang3artifactId>
            dependency>
    
            
            <dependency>
                <groupId>com.alibabagroupId>
                <artifactId>fastjsonartifactId>
                <version>1.2.75version>
            dependency>
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>mybatis-plus-boot-starterartifactId>
                <version>3.4.0version>
            dependency>
    
            
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
                <scope>runtimescope>
            dependency>
    
    • 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
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

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

  • 相关阅读:
    【C++】传递‘类非静态成员函数’用作回调函数
    .NET高级技术_04正则、序列化、XML
    HTML+CSS美食静态网页设计——简单牛排美食餐饮(9个页面)公司网站模板企业网站实现
    Mathorcup数学建模竞赛第四届-【妈妈杯】B题:推荐书籍(附解析思路和MATLAB代码)
    【附源码】计算机毕业设计SSM水库洪水预报调度系统
    Linux中FTP安装
    记一次线程爆满导致服务器崩溃的问题排查
    堆以及堆的实现
    Linux基础(三)----->权限理解和文件属性
    FFmpeg修复受损视频
  • 原文地址:https://blog.csdn.net/qq_34846877/article/details/126653316