web-dev-qa-db-fra.com

Spring Data Redis Expire Key

J'ai une application One Spring Hibernate. Dans mon application, je suis récemment implémenté Spring Data Redis.

spring-servlet.xml
<!-- redis connection factory -->
<bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true"/>

<!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" 
    p:connection-factory-ref="jedisConnFactory"/>

Et cette redisTemplate utiliser dans ma classe ServiceImpl.

RedisServiceImpl

@Autowired
private RedisTemplate<String, T> redisTemplate;

public RedisTemplate<String, T> getRedisTemplate() {
    return redisTemplate;
}

public void setRedisTemplate(RedisTemplate<String, T> redisTemplate) {
    this.redisTemplate = redisTemplate;
}

Maintenant, j'ai ajouté des données dans redisServer comme ceci

public void putData(String uniqueKey, String key, Object results) {

    redisTemplate.opsForHash().put(uniqueKey, key, results);
}

Maintenant, je veux supprimer la clé Expire.

Je recherche dans Google, mais dans Google tous disent comme ça

redisTemplate.expire(key, timeout, TimeUnit);

Dans cette méthode d'expiration, nous devons fournir uniqueKey au lieu de key. Mais je dois expirer key au lieu de uniqueKey.

Alors aidez-moi, que puis-je faire pour expirer Key?

7
Akash Chavda

J'utilise Redis Version 3.2.100.

Au lieu de template redis , utilisez Gestionnaire de cache Redis , transmettez redistemplate à cacheManager et utilisez la propriété set expires à laquelle correspond essentiellement la carte de String & Long, vous pouvez ajouter un nom de cache et définir son délai d'expiration vivre (TTL).

Vous pouvez utiliser setDefaultExpiration method of cacheManager pour définir le même délai d'expiration pour tout le cache.

@SuppressWarnings({ "rawtypes", "unused" })
@Configuration
@EnableCaching(proxyTargetClass = true, mode = AdviceMode.ASPECTJ, order = 1)
@PropertySource("classpath:/application.properties")
public class CacheConfigImpl extends CachingConfigurerSupport {

    private @Value("${redis.ip}") String redisHost;
    private @Value("${redis.port}") int redisPort;

     private static final Map<String, Long> cacheMap = new HashMap<String, Long>();
    static {
        cacheMap.put("method1cache", 600L);
        cacheMap.put("method2cache", 600L);
        cacheMap.put("method3cache", 800L);
    }

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    public JedisConnectionFactory redisConnectionFactory() {
        JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
        redisConnectionFactory.setHostName(CustomPropertyLoader.getProperty("redis.ip"));
        redisConnectionFactory.setPort(Integer.parseInt(CustomPropertyLoader.getProperty("redis.port")));
        return redisConnectionFactory;
    }

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean(name = "RCacheManager")
    public CacheManager cacheManager(RedisTemplate redisTemplate) {

        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        cacheManager.setExpires(cacheMap);
        cacheManager.setUsePrefix(true);
        final String redis_client_name = CustomPropertyLoader.getProperty("redis.client.name");
        cacheManager.setCachePrefix(new RedisCachePrefix() {
            private final RedisSerializer<String> serializer = new StringRedisSerializer();
            private final String delimiter = ":";

            public byte[] prefix(String cacheName) {
                return this.serializer
                        .serialize(redis_client_name.concat(this.delimiter).concat(cacheName).concat(this.delimiter));
            }
        });
        return cacheManager;
    }
    }
5
Swadeshi

En fait, vous pouvez le faire avec Redisson framework (grille de données basée sur Redis pour Java) en utilisant l’objet RMapCache. Il permet de définir ttl et maxIdle par entrée de carte. Exemple:

// implements Java.util.concurrent.ConcurrentMap interface
RMapCache<String, SomeObject> map = redisson.getMapCache("anyMap");

// ttl = 10 minutes, 
map.put("key1", new SomeObject(), 10, TimeUnit.MINUTES);
// ttl = 10 minutes, maxIdleTime = 10 seconds
map.put("key1", new SomeObject(), 10, TimeUnit.MINUTES, 10, TimeUnit.SECONDS);
3
Nikita Koksharov

En réalité, vous ne pouvez pas expirer ou définir le TTL pour des clés individuelles à l'intérieur du hachage Redis. Vous pouvez uniquement expirer ou définir TTL le hachage complet. si vous voulez supporter cela, vous devez changer votre structure de données. 

Voici le lien pour pourquoi ce n'est pas possible; et ci-dessous quelques extraits de Redis expire

Autant que je sache, Redis se préoccupe de la performance plutôt que des fonctionnalités. Ce sera échec du but de l'implémentation de hachage efficace en mémoire dans redis . Depuis le hachage, les champs valeur-clé ne sont pas toujours représentés comme étant complets feature redis object (ils peuvent être stockés sous forme de tableau linéaire lorsque hash est petit pour économiser de la mémoire), ainsi le champ hash key ne peut pas avoir de durée de vie.

De plus, ce lien Permet de définir un champ d’expiration sur un hachage pourrait vous aider à modifier la structure de vos données pour gérer l’expiration.

2
Santosh Joshi

Pour définir TTL pour les clés, vous pouvez créer plusieurs beans de cacheManager et définir TTL pour un bean individuel. Ensuite, selon votre utilisation, vous pouvez utiliser le gestionnaire de cache requis . Voici ce que j'ai implémenté.

@Configuration("cacheConfig")
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport{


    @Bean
    public JedisConnectionFactory redisConnectionFactory() {
        System.out.println("redisConnectionFactory");
        JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();

        // Defaults
        redisConnectionFactory.setHostName("127.0.0.1");
        redisConnectionFactory.setPort(6379);
        return redisConnectionFactory;
    }

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
        System.out.println("redisTemplate");
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
        redisTemplate.setConnectionFactory(cf);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }

    @Bean
    @Primary
    public CacheManager cacheManager2(RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        // Number of seconds before expiration. Defaults to unlimited (0)
        cacheManager.setDefaultExpiration(20);
        cacheManager.setUsePrefix(true);
        return cacheManager;
    }


    @Bean
    public CacheManager cacheManager1(RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        // Number of seconds before expiration. Defaults to unlimited (0)
        cacheManager.setDefaultExpiration(60);
        cacheManager.setUsePrefix(true);
        return cacheManager;
    }

}

Pour utiliser les beans cachemanager créés ci-dessus,

@Cacheable(value = "users", key = "#userId.toString()", cacheManager ="cacheManager2")
    @RequestMapping(value = "/{userId}", method = RequestMethod.GET)
    public User getUser(@PathVariable String userId) {
        LOG.info("Getting user with ID {}.: "+userId);
      return userService.fetchUserDataonUsers(userId);
    }


@Cacheable(value = "users", key = "#userId.toString()", cacheManager ="cacheManager1")
    @RequestMapping(value = "data/{userId}", method = RequestMethod.GET)
    public String getUserData(@PathVariable String userId) {
        LOG.info("Getting user with ID getUserData {}.: "+userId);
      return userService.fetchUserDataonUsers(userId).toString();
    }

lorsque nous définissons cacheManager ="cacheManager2" dans @Cacheable, il utilisera TTL défini pour cacheManager2 défini dans la configuration. Idem pour cacheManager1

2
Akanksha Sharma

Vous pouvez adopter Quartz à cette fin (implémenter ttl pour un enregistrement Redis) . Si vous utilisez Spring Boot, il configure automatiquement Scheduler pour vous. Ainsi, vous pouvez le transférer directement à votre couche service.

@Autowired
private Scheduler scheduler;

Ensuite, vous devez implémenter un travail comme celui-ci (dans cet exemple, j'utilise Spring Redis Data):

@Slf4j
@Component
public class RemoveExpiredRecordJob implements Job {

@Autowired
public RedisRepository redisRepository;

@Override
public void execute(JobExecutionContext jobExecutionContext) {
    String key = jobExecutionContext
            .getJobDetail()
            .getKey()
            .getName();
    redisRepository.deleteById(key);
    log.info("Record removed due timeout :: {}", key);
}

}

Ensuite, vous pouvez encapsuler une logique pour créer JobDetail et Trigger

@Component
public class SchedulerComponentBuilder {

    public JobDetail getJobDetail (String key, Class<? extends org.quartz.Job> clazz) {
        return JobBuilder.newJob().ofType(clazz)
                .storeDurably(false)
                .withIdentity(key)
                .withDescription("This key will be removed from Redis store when time expires.")
                .build();
    }

    public Trigger getTrigger(int ttl, JobDetail jobDetail) {
        Java.util.Calendar calendar = Java.util.Calendar.getInstance();
        calendar.add(Java.util.Calendar.SECOND, ttl);
        return TriggerBuilder.newTrigger().forJob(jobDetail)
                .withDescription("This trigger fires once to remove an expired record from Redis store.")
                .startAt(calendar.getTime())
                .build();
    }
}

Et enfin, juste après que vous ayez enregistré votre enregistrement dans le référentiel Redis, vous devez planifier un travail pour supprimer cet enregistrement (uniqueKey) comme suit:

@Autowired
private SchedulerComponentBuilder schedulerComponentBuilder;

private void schedule(String uniqueKey, int ttl) {
    try {
        JobDetail jobDetail = schedulerComponentBuilder.getJobDetail(uniqueKey, RemoveExpiredRecordJob.class);
        Trigger jobTrigger = schedulerComponentBuilder.getTrigger(ttl, jobDetail);
        scheduler.scheduleJob(jobDetail,jobTrigger);
        log.info("Job is scheduled :: {}", jobDetail);
    } catch (SchedulerException e) {
        log.error("Filed to schedule a job {}", e);
        throw new RuntimeException(e);
    }
}
1
Andreas Gelever