Spring Cache与Redis - 当连接Redis失败时如何优雅地处理或跳过缓存

16
我在我的Spring应用程序中启用了缓存并使用Redis来实现这个目的。但是,每当发生连接故障时,应用程序就会停止工作,而我认为它最好跳过缓存并继续正常执行流程。
那么,有没有人知道如何在Spring中优雅地做到这一点?
下面是我得到的异常信息。
Caused by: org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
3个回答

8
自Spring Framework 4.1开始,有一个 CacheErrorHandler 可以处理此类异常。更多详情请参阅javadoc
您可以通过让您的@Configuration类扩展CachingConfigurerSupport(参见errorHandler())来注册它。

非常感谢您的建议。我的 @Configuration 类已经扩展了 SpringBootServletInitializer,因此我尝试直接从我的 @Configuration 类实现 CacheErrorHandler,而不是继承它。然而,它似乎无法处理 RedisConnectionFailureException 等任何异常。 - Peter Bean
你在哪里看到了关于 SpringBootServletInitializer 的引用?我写了 CachingConfigurerSupport - 你需要使用 Spring Boot 1.2 (Spring 4.1) 才能使用它。 - Stephane Nicoll
1
CacheErrorHandler仅在缓存操作期间使用。Redis连接故障可能发生在更高层? - Jaymes Bearden
嗯?你说的“higher up”是什么意思? - Stephane Nicoll
1
我认为他可能是指当连接失败时,CacheErrorHandler可能不会被触发。 - Peter Bean
显示剩余3条评论

3
你可以像Stephane Nicoll建议的那样使用CacheErrorHandler。但是,在Redis Cache Config中,你需要确保将RedisCacheManager transactionAware设置为false(以确保在执行缓存部分时事务尽早提交,错误被CacheErrorHandler捕获,并且不要等到执行结束再跳过CacheErrorHandler部分)。将transactionAware设置为false的函数如下:
    @Bean
    public RedisCacheManager redisCacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
        JdkSerializationRedisSerializer redisSerializer = new JdkSerializationRedisSerializer(getClass().getClassLoader());

        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(redisDataTTL))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer));

        redisCacheConfiguration.usePrefix();

        RedisCacheManager redisCacheManager = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(lettuceConnectionFactory)
                .cacheDefaults(redisCacheConfiguration)
                .build();

        redisCacheManager.setTransactionAware(false);
        return redisCacheManager;
    }

它对我有效,但我担心将缓存排除在事务之外。 - jonathan

-1

与Stephane所提到的类似,我通过在try catch块中消耗错误来完成了这个任务。添加了一个备用机制,如果Redis没有启动或数据不存在,则从数据库中获取数据。(稍后如果找到相同的数据,则将其添加到Redis中(如果它已经启动)以保持一致性。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接