springboot整合redis过期key监听实现订单过期的项目实践
作者:一只牛博
业务场景说明
对于订单问题,那些下单了但是没有去支付的(占单情况),不管对于支付宝还是微信都有订单的过期时间设置,但是对于我们自己维护的订单呢。两种方案:被动修改,主动修改。这里仅仅说明对于主动修改的监听实现
修改redis的配置文件redis.conf(好像不改也可以)
K:keyspace事件,事件以__keyspace@<db>__为前缀进行发布;
E:keyevent事件,事件以__keyevent@<db>__为前缀进行发布;
g:一般性的,非特定类型的命令,比如del,expire,rename等;
$:字符串特定命令;
l:列表特定命令;
s:集合特定命令;
h:哈希特定命令;
z:有序集合特定命令;
x:过期事件,当某个键过期并删除时会产生该事件;
e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件;
A:g$lshzxe的别名,因此”AKE”意味着所有事件
pom依赖坐标的引入
<!--版本号说明。这里我使用的是<jedis.version>2.9.3</jedis.version>,<spring.boot.version>2.3.0.RELEASE</spring.boot.version>--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>${jedis.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>${spring.boot.version}</version> </dependency>
这里可能会存在的依赖冲突问题是与io.netty
RedisConfig的配置
package test.bo.work.config.redis; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 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; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import test.bo.work.util.StringUtil; /** * @author xiaobo */ @Configuration @EnableAutoConfiguration public class JedisConfig { private static final Logger LOGGER = LoggerFactory.getLogger(JedisConfig.class); @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.password}") private String password; @Value("${spring.redis.timeout}") private int timeout; @Value("${spring.redis.jedis.pool.max-active}") private int maxActive; @Value("${spring.redis.jedis.pool.max-wait}") private int maxWait; @Value("${spring.redis.jedis.pool.max-idle}") private int maxIdle; @Value("${spring.redis.jedis.pool.min-idle}") private int minIdle; @Bean public JedisPool redisPoolFactory() { try { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxIdle(maxIdle); jedisPoolConfig.setMaxWaitMillis(maxWait); jedisPoolConfig.setMaxTotal(maxActive); jedisPoolConfig.setMinIdle(minIdle); // JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password); String pwd = StringUtil.isBlank(password) ? null : password; JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, pwd,6); LOGGER.info("初始化Redis连接池JedisPool成功!地址: " + host + ":" + port); return jedisPool; } catch (Exception e) { LOGGER.error("初始化Redis连接池JedisPool异常:" + e.getMessage()); } return null; } @Bean public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); return container; } }
监听器实现
package test.bo.work.config.redis; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.listener.KeyExpirationEventMessageListener; import org.springframework.data.redis.listener.PatternTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.stereotype.Component; import java.nio.charset.StandardCharsets; /** * @author xiaobo */ @Component @Slf4j public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener { public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) { super(listenerContainer); log.info("Redis Key Expiration Listener has been initialized."); } @Override public void onMessage(Message message, byte[] pattern) { String expiredKey = message.toString(); log.error(expiredKey); // 判断是否是想要监听的过期key if (expiredKey.startsWith(KuoCaiConstants.ORDER_REDIS_PREFIX)) { // 根据过期redisKey获取订单号 String transactionOrderId = expiredKey.substring(KuoCaiConstants.ORDER_REDIS_PREFIX.length()); transactionOrderService.updateTransactionOrderStatusByRedis(Long.valueOf(transactionOrderId)); } } }
【注意】可能存在的问题(监听事件失效)
【警告】存在的问题
自己自定义了库,如下代码
@Override protected void doRegister(RedisMessageListenerContainer listenerContainer) { // 针对db6进行监听 listenerContainer.addMessageListener(this, new PatternTopic("__keyevent@6__:expired")); }
这种情况,如果你存入的key不在db6,那么你就看不到监听触发事件(这里并不是失效,只是说可能出现的你认为失效的情况)
使用了默认的连接工厂,但是配置文件中又没有相关定义
首先解释一下,默认情况下,Spring Boot使用Jedis作为Redis客户端,并且会自动根据application.properties或application.yml配置文件中的
spring.redis
属性来创建连接工厂。如果没有指定这些属性,则会使用默认的localhost:6379
作为Redis服务器地址。如果你想要连接到其他的Redis服务器,可以在配置文件中设置
spring.redis.host
和spring.redis.port
属性来指定Redis服务器的地址和端口号。
对于以上情况可以自定义工厂然后注入即可(上面的JedisConfig.java文件)
@Bean public JedisConnectionFactory jedisConnectionFactory() { RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); redisStandaloneConfiguration.setHostName(host); redisStandaloneConfiguration.setDatabase(db); redisStandaloneConfiguration.setPassword(RedisPassword.of(password)); redisStandaloneConfiguration.setPort(port); return new JedisConnectionFactory(redisStandaloneConfiguration); } @Bean public RedisMessageListenerContainer container(JedisConnectionFactory jedisConnectionFactory) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(jedisConnectionFactory); return container; }
Redis的Key事件通知机制默认是异步的,即Redis会在Key过期时发送事件通知给所有监听者,但是不能保证监听者一定会及时接收到通知。如果您的应用程序需要在Key过期后立即处理相关操作,可能需要使用其他方式来实现。
在Redis中,Key的过期时间只是一个近似的时间,它并不是精确的,因此不能保证过期时间到达时就一定会立即过期。如果您需要在Key过期后立即处理相关操作,建议您使用其他方式来实现,例如使用定时任务或轮询方式检查过期Key。
在Redis中,Key的过期时间不能被取消或重置。如果您在设计时考虑到Key的过期时间可能需要修改,建议您使用其他方式来实现。
当Redis中的Key被持久化到磁盘上时,过期时间可能会受到影响,因为过期时间的计算是基于系统时间的,如果系统时间发生变化,过期时间可能会出现不准确的情况。因此,建议您使用其他方式来处理需要精确过期时间的场景。
到此这篇关于springboot整合redis过期key监听实现订单过期的项目实践的文章就介绍到这了,更多相关springboot redis过期key监听订单过期内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- springboot+redis过期事件监听实现过程解析
- Spring Boot监听Redis Key失效事件实现定时任务的示例
- spring boot+redis 监听过期Key的操作方法
- SpringBoot如何整合redis实现过期key监听事件
- SpringBoot如何监控Redis中某个Key的变化(自定义监听器)
- SpringBoot中使用Redis Stream实现消息监听示例
- SpringBoot如何监听redis Key变化事件案例详解
- SpringBoot监听Redis key失效事件的实现代码
- 如何监听Redis中Key值的变化(SpringBoot整合)
- SpringBoot使用Redis单机版过期键监听事件的实现示例