Maison >base de données >Redis >Comment Redis surveille-t-il les clés expirées ?
Regardons d'abord une question :
Comment gérer l'annulation automatique d'une commande expirée, comme par exemple le changement automatique du statut de la commande si la commande n'est pas payée pendant 30 minutes ?
Solution :
Vous pouvez utiliser le mécanisme d'expiration automatique de la clé naturelle de Redis. Lorsque vous passez une commande, écrivez l'identifiant de la commande dans Redis. Le délai d'expiration est de 30 minutes. statut après 30 minutes Si le paiement n'est pas effectué, il sera traité mais la clé a expiré. Y a-t-il une notification de redis ? La réponse est oui.
Activer le rappel d'expiration de la clé Redis
Modifier la configuration des événements liés à Redis. Recherchez le fichier de configuration redis redis.conf et vérifiez l'élément de configuration "notify-keyspace-events". Sinon, ajoutez "notify-keyspace-events Ex". S'il y a une valeur, ajoutez Ex. Les paramètres pertinents sont décrits comme. suit :
K:keyspace事件,事件以__keyspace@<db>__为前缀进行发布; E:keyevent事件,事件以__keyevent@<db>__为前缀进行发布; g:一般性的,非特定类型的命令,比如del,expire,rename等; $:字符串特定命令; l:列表特定命令; s:集合特定命令; h:哈希特定命令; z:有序集合特定命令; x:过期事件,当某个键过期并删除时会产生该事件; e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件; A:g$lshzxe的别名,因此”AKE”意味着所有事件。
Test Redis :
Ouvrez un redis-cli et surveillez l'événement d'expiration de clé de db0
127.0.0.1:6379> PSUBSCRIBE __keyevent@0__:expired Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "__keyevent@0__:expired" 3) (integer) 1
Ouvrez un autre redis-cli et envoyer des clés expirées programmées
127.0.0.1:6379> setex test_key 3 test_value
Observez le redis-cli précédent et vous constaterez que la keytest_key expirée a été reçue, mais la valeur expirée test_value
127.0.0.1:6379> PSUBSCRIBE __keyevent@0__:expired Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "__keyevent@0__:expired" 3) (integer) 1 1) "pmessage" 2) "__keyevent@0__:expired" 3) "__keyevent@0__:expired" 4) "test_key"
est utilisée dans springboot
Ajoutez la dépendance
<!-- redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
au pom pour définir la configuration RedisListenerConfig
import edu.zut.ding.listener.RedisExpiredListener;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.PatternTopic;import org.springframework.data.redis.listener.RedisMessageListenerContainer;/** * @Author lsm * @Date 2018/10/27 20:56 */@Configurationpublic class RedisListenerConfig { @Bean RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory);// container.addMessageListener(new RedisExpiredListener(), new PatternTopic("__keyevent@0__:expired")); return container; } }
pour définir l'écouteur et implémenter l'interface KeyExpirationEventMessageListener. Vérifiez le code source et constatez que cette interface. surveille tous les événements d'expiration de la base de données keyevent@*:expired"
import edu.zut.ding.constants.SystemConstant;import edu.zut.ding.enums.OrderState;import edu.zut.ding.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;/** * 监听所有db的过期事件__keyevent@*__:expired" * @author lsm */@Componentpublic class RedisKeyExpirationListener extends KeyExpirationEventMessageListener { public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) { super(listenerContainer); } /** * 针对redis数据失效事件,进行数据处理 * @param message * @param pattern */ @Override public void onMessage(Message message, byte[] pattern) { // 用户做自己的业务处理即可,注意message.toString()可以获取失效的key String expiredKey = message.toString(); if(expiredKey.startsWith("Order:")){ //如果是Order:开头的key,进行处理 } } }
Ou ouvrez le conteneur.addMessageListener(new RedisExpiredListener(), new PatternTopic("__keyevent@0__:expired")); commentez dans RedisListenerConfig, puis définissez le écoutez et surveillez l'événement __keyevent@0__:expired, qui est l'événement d'expiration db0. La définition de cet endroit est relativement flexible, vous pouvez définir les événements à surveiller
import org.springframework.data.redis.connection.Message;import org.springframework.data.redis.connection.MessageListener;/** * @author lsm */public class RedisExpiredListener implements MessageListener { /** * 客户端监听订阅的topic,当有消息的时候,会触发该方法; * 并不能得到value, 只能得到key。 * 姑且理解为: redis服务在key失效时(或失效后)通知到java服务某个key失效了, 那么在java中不可能得到这个redis-key对应的redis-value。 * * 解决方案: * 创建copy/shadow key, 例如 set vkey "vergilyn"; 对应copykey: set copykey:vkey "" ex 10; * 真正的key是"vkey"(业务中使用), 失效触发key是"copykey:vkey"(其value为空字符为了减少内存空间消耗)。 * 当"copykey:vkey"触发失效时, 从"vkey"得到失效时的值, 并在逻辑处理完后"del vkey" * * 缺陷: * 1: 存在多余的key; (copykey/shadowkey) * 2: 不严谨, 假设copykey在 12:00:00失效, 通知在12:10:00收到, 这间隔的10min内程序修改了key, 得到的并不是 失效时的value. * (第1点影响不大; 第2点貌似redis本身的Pub/Sub就不是严谨的, 失效后还存在value的修改, 应该在设计/逻辑上杜绝) * 当"copykey:vkey"触发失效时, 从"vkey"得到失效时的值, 并在逻辑处理完后"del vkey" * */ @Override public void onMessage(Message message, byte[] bytes) { byte[] body = message.getBody();// 建议使用: valueSerializer byte[] channel = message.getChannel(); System.out.print("onMessage >> " ); System.out.println(String.format("channel: %s, body: %s, bytes: %s" ,new String(channel), new String(body), new String(bytes))); } }.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!