springboot 使用 redis 監聽 key 的過期回調( 模擬設置訂單號超時時間, 觸發修改訂單狀態業務邏輯)

本文Demo地址:https://gitee.com/wslxm/spring-boot-redis

一、redis 配置文件 redis.conf 修改如下

 notify-keyspace-events ""  修改爲  notify-keyspace-events Ex

具體參考
在這裏插入圖片描述

二、springboot 使用redis 設置key失效監聽配置

1、配置監聽beng

package cn.ws.config;


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;
    }
}

2、配置redis-key 失效監聽類

package cn.ws.config;


import cn.ws.constants.OrderConstants;
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;

@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    /**
     * Redis-key失效監聽事件,所有key 失效都會走此方法
     *
     * @param message
     * @param pattern
     */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        //  獲取失效的key
        String expiredKey = message.toString();
      
        //  指定key 的前綴=xxxxxx,處理對應業務邏輯,可看步驟三生成訂單號:public static final String   ORDER_OVER_TIME_KEY= "order-over-time:";
        if (expiredKey.indexOf(OrderConstants.ORDER_OVER_TIME_KEY) != -1) {
            String[] orderOn = expiredKey.split(":");
            System.out.println("訂單號: "+orderOn[1] +"超時"  );
        }
        System.out.println(expiredKey);
    }
}

如果只想配置監聽, 請無視下方內容

三、Redis 訂單號生成分佈式唯一訂單號工具類

此工具類每秒可生成999999 個訂單號,訂單號位數爲20位

  • 實現思路:使用14位時間戳 + 4位自增Id (位數不夠自動填充0)
  • 獲得時間戳:new SimpleDateFormat(“yyyyMMddHHmmss”).format(new Date());
  • 獲取redis自增id:opsForValue().increment(newKey, delta)
  • 補位填充0到4位數:String.format("%04d", increment);
  • redis集羣:使用命令設置自增歩長,如步長=2,自增值= 1,3,5,7,9
  • redis宕機處理:採用14位時間戳+ 4位隨機數生成訂單號

1、訂單相關常量類

package cn.ws.constants;

/**
 * TODO  訂單常量類
 *
 * @author ws
 * @mail [email protected]
 * @date 2020/2/21 0021 16:02
 */
public class OrderConstants {


    /**
     * 訂單生成redis-key前綴
     */
   public static final String ORDER_ON = "order-on";
    /**
     * 訂單生成redis-key前綴
     */
   public static final String   ORDER_OVER_TIME_KEY= "order-over-time:";
    /**
     * 訂單有效期(秒)
     */
   // public static final Long ORDER_OVER_TIME = 30L * 60L;
    public static final Long ORDER_OVER_TIME = 10L;
}

2、訂單號生成工具 RedisOrderIDGenerate

package cn.ws.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * TODO  分佈式架構獲取唯一訂單號(基於redis),如果redis 集羣,需設置自增歩長,使用命令設置
 *
 * @author ws
 * @mail [email protected]
 * @date 2020/2/20 0020 15:02
 */
@Configuration
public class RedisOrderIDGenerate {


    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * TODO 獲取唯一Id(20位)
     *
     * @param key   redis-key前綴
     * @param delta 默認初始自增值
     * @return java.lang.String
     * @author ws
     * @mail [email protected]
     * @date 2020/2/20 0020 15:59
     */
    public String getOrderId(String key, Long delta) {
        try {
            // delta爲空默認值1
            if (null == delta) {
                delta = 1L;
            }
            // 生成14位的時間戳(每秒使用新的時間戳當key)
            String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            // 獲得redis-key
            String newKey = key + ":" + timeStamp;
            // 獲取自增值(時間戳+自定義key)
            Long increment = redisTemplate.opsForValue().increment(newKey, delta);
            // 設置時間戳生成的key的有效期爲2秒
            redisTemplate.expire(newKey, 2, TimeUnit.SECONDS);
            // 獲取訂單號,時間戳 + 唯一自增Id( 6位數,不過前方補0)
            return timeStamp + String.format("%06d", increment);
        } catch (Exception e) {
            // redis 宕機時採用時間戳加隨機數
            String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
            Random random = new Random();
            //14位時間戳到秒 + 4位隨機數
            timeStamp += random.nextInt(10) + random.nextInt(10) + random.nextInt(10) + random.nextInt(10);
            return timeStamp;
        }
    }
}

3、訂單號生成參數controller


/**
 * TODO  生成訂單號並測試並添加訂單過期時間
 *
 * @author ws
 * @mail [email protected]
 * @date 2020/2/21 0021 16:03
 */
@RestController
public class TestController {

    @Autowired
    private RedisOrderIDGenerate redisOrderIDGenerate;
  
    // redis 工具類,本次不做說明
    @Autowired
    private RedisUtil redisUtil;


    @GetMapping("/test")
    public String test() {
        // 獲取訂單號
        String orderOn = redisOrderIDGenerate.getOrderId(OrderConstants.ORDER_ON, 1L);
        // 設置訂單有效期30秒
        redisUtil.set(OrderConstants.ORDER_OVER_TIME_KEY + orderOn, 0, OrderConstants.ORDER_OVER_TIME);
        return orderOn;
    }
}
發佈了200 篇原創文章 · 獲贊 30 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章