springboot整合redis過期key監(jiān)聽實現(xiàn)訂單過期的項目實踐
業(yè)務場景說明
對于訂單問題,那些下單了但是沒有去支付的(占單情況),不管對于支付寶還是微信都有訂單的過期時間設置,但是對于我們自己維護的訂單呢。兩種方案:被動修改,主動修改。這里僅僅說明對于主動修改的監(jiān)聽實現(xiàn)
修改redis的配置文件redis.conf(好像不改也可以)
K:keyspace事件,事件以__keyspace@<db>__為前綴進行發(fā)布;
E:keyevent事件,事件以__keyevent@<db>__為前綴進行發(fā)布;
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; } }
監(jiān)聽器實現(xiàn)
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); // 判斷是否是想要監(jiān)聽的過期key if (expiredKey.startsWith(KuoCaiConstants.ORDER_REDIS_PREFIX)) { // 根據(jù)過期redisKey獲取訂單號 String transactionOrderId = expiredKey.substring(KuoCaiConstants.ORDER_REDIS_PREFIX.length()); transactionOrderService.updateTransactionOrderStatusByRedis(Long.valueOf(transactionOrderId)); } } }
【注意】可能存在的問題(監(jiān)聽事件失效)
【警告】存在的問題
自己自定義了庫,如下代碼
@Override protected void doRegister(RedisMessageListenerContainer listenerContainer) { // 針對db6進行監(jiān)聽 listenerContainer.addMessageListener(this, new PatternTopic("__keyevent@6__:expired")); }
這種情況,如果你存入的key不在db6,那么你就看不到監(jiān)聽觸發(fā)事件(這里并不是失效,只是說可能出現(xiàn)的你認為失效的情況)
使用了默認的連接工廠,但是配置文件中又沒有相關定義
首先解釋一下,默認情況下,Spring Boot使用Jedis作為Redis客戶端,并且會自動根據(jù)application.properties或application.yml配置文件中的
spring.redis
屬性來創(chuàng)建連接工廠。如果沒有指定這些屬性,則會使用默認的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過期時發(fā)送事件通知給所有監(jiān)聽者,但是不能保證監(jiān)聽者一定會及時接收到通知。如果您的應用程序需要在Key過期后立即處理相關操作,可能需要使用其他方式來實現(xiàn)。
在Redis中,Key的過期時間只是一個近似的時間,它并不是精確的,因此不能保證過期時間到達時就一定會立即過期。如果您需要在Key過期后立即處理相關操作,建議您使用其他方式來實現(xiàn),例如使用定時任務或輪詢方式檢查過期Key。
在Redis中,Key的過期時間不能被取消或重置。如果您在設計時考慮到Key的過期時間可能需要修改,建議您使用其他方式來實現(xiàn)。
當Redis中的Key被持久化到磁盤上時,過期時間可能會受到影響,因為過期時間的計算是基于系統(tǒng)時間的,如果系統(tǒng)時間發(fā)生變化,過期時間可能會出現(xiàn)不準確的情況。因此,建議您使用其他方式來處理需要精確過期時間的場景。
到此這篇關于springboot整合redis過期key監(jiān)聽實現(xiàn)訂單過期的項目實踐的文章就介紹到這了,更多相關springboot redis過期key監(jiān)聽訂單過期內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
移動開發(fā)Spring Boot外置tomcat教程及解決方法
這篇文章主要介紹了移動開發(fā)SpringBoot外置tomcat教程,需要的朋友可以參考下2017-11-11為什么阿里要慎重使用ArrayList中的subList方法
這篇文章主要介紹了為什么要慎重使用ArrayList中的subList方法,subList是List接口中定義的一個方法,該方法主要用于返回一個集合中的一段、可以理解為截取一個集合中的部分元素,他的返回值也是一個List。,需要的朋友可以參考下2019-06-06Spring Boot 接口參數(shù)加密解密的實現(xiàn)方法
這篇文章主要介紹了Spring Boot 接口參數(shù)加密解密的實現(xiàn)方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03Mybatis-Plus使用@TableField實現(xiàn)自動填充日期的代碼示例
數(shù)據(jù)庫中經常有create_time,update_time兩個字段,在代碼中設置時間有點太麻煩了?mybatis-plus可以幫我們自動填充,本文主要介紹了Mybatis-Plus使用@TableField實現(xiàn)自動填充日期的代碼示例,感興趣的可以了解一下2022-04-04Java用jxl讀取excel并保存到數(shù)據(jù)庫的方法
這篇文章主要為大家詳細介紹了Java用jxl讀取excel并保存到數(shù)據(jù)庫的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10Java命令設計模式優(yōu)雅解耦命令和執(zhí)行提高代碼可維護性
本文介紹了Java命令設計模式,它將命令請求封裝成對象,以達到解耦命令請求和執(zhí)行者的目的,從而提高代碼可維護性。本文詳細闡述了該模式的設計原則、實現(xiàn)方法和優(yōu)缺點,并提供了實際應用場景和代碼示例,幫助讀者深入理解和應用該模式2023-04-04Java使用阿里云接口進行身份證實名認證的示例實現(xiàn)
這篇文章主要介紹了使用阿里云接口進行身份證實名認證的示例實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07