当前位置: 首页 > 知识库问答 >
问题:

Spring-data-redis cache-callbackend method即使我使用CustomizeRedisCacheManager也会缓存数据

楚建柏
2023-03-14

我使用的是Spring-data-redis cache(1.6.1),Jredis Client2.7.3。我们希望启用故障转移。如果redis服务器停机,我希望应用程序继续工作

1)如果我使用spring-data xml配置,redis cache工作良好。它调用后端,缓存数据,然后在第二次调用时不调用后端。但是,我不知道如何捕获redis异常,如果服务器使用xml配置关闭,并返回null,以便应用程序继续工作。没有足够的文档。(这个解决方案不起作用)

2)我已经使用Java配置了redis缓存,在这种情况下,我能够捕获故障转移excetpion,但是Spring-data-redis,在redis缓存正常工作的情况下,仍然会继续调用后端数据库方法,所以它应该调用后端方法并缓存数据,第二次调用不应该返回到后端数据库。

所以它对所有的请求进行缓存和调用后端数据库方法。

我想知道是否有人面临过这个问题。或者在后端Redis服务器关闭时如何对spring-data-redis进行故障转移。

我已经附上了示例代码。

Configuration
@EnableCaching
@ComponentScan("com.mkyong.helloworld.service")
@PropertySource("classpath:/redis.properties")
public class AppConfig extends CachingConfigurerSupport{
    private @Value("${redis.host-name}") String redisHostName;
    private @Value("${redis.port}") int redisPort;
//  private @Value("${cache.expire}") long cacheExpire;
//  private @Value("${cache.name}") String cacheName; 


private Log logger = LogFactory.getLog(getClass());

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

 @Bean
 JedisConnectionFactory jedisConnectionFactory() {
     JedisConnectionFactory factory = new JedisConnectionFactory();
     factory.setHostName(redisHostName);
     factory.setPort(redisPort);
     factory.setUsePool(true);
     return factory;
 }

 @Bean
 RedisTemplate<Object, Object> redisTemplate() {
     RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
     redisTemplate.setConnectionFactory(jedisConnectionFactory());
     return redisTemplate;
 }

 @Bean
 public CacheManager cacheManager() {
//     return new RedisCacheManager(redisTemplate());
//      logger.debug("Calling Redis CustomRedisCacheManager()" );
//     return new CustomRedisCacheManager(redisTemplate());
     logger.debug("START: operation=cacheManager");
     UUID transactionId = UUID.randomUUID();
     long startTime = System.currentTimeMillis();
     long stopTime=0;
     long elapsedTime=0;
     String userTokenCache1="descCache";
     String userTokenCache2="titleCache";
     //Long expiration = environment.getProperty("cache.default.timeout", Long.class);
     Long expiration = 360000L;
     Map<String, Long> expires = new ConcurrentHashMap<>(1);
     expires.put(userTokenCache1, expiration);
     expires.put(userTokenCache2, expiration);
     CustomRedisCacheManager cacheMgr = new CustomRedisCacheManager( redisTemplate() );
     cacheMgr.setExpires(expires);
//   //cacheMgr.setDefaultExpiration(expires);
//   cacheMgr.setCacheNames(Arrays.asList(userTokenCache));
     stopTime = System.currentTimeMillis();
     elapsedTime = stopTime - startTime;
     logger.debug("Cache Name = " + userTokenCache1 + " cacheExpire=" + userTokenCache1 );
     logger.debug("END: transcation_id=" + transactionId + " operation=cacheManager" + " status=Completed, execution_time=" + elapsedTime );

     return cacheMgr;
 }

// @Bean // important!
// @Override
// public CacheErrorHandler errorHandler() {
//     // configure and return CacheErrorHandler instance
//   CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
//      
//      @Override
//      public void handleCachePutError(RuntimeException exception, Cache cache,
//              Object key, Object value) {
//          // TODO Auto-generated method stub
//          logger.warn("As the Redis Cache server may be down. Unable to save Cache..." );
//      }
//      
//      @Override
//      public void handleCacheGetError(RuntimeException exception, Cache cache,
//              Object key) {
//          // TODO Auto-generated method stub
//          logger.warn("As the Redis Cache server may be down. Fetching Data from the backend..." );
//      
//      }
//      
//      @Override
//      public void handleCacheEvictError(RuntimeException exception, Cache cache,
//              Object key) {
//          // TODO Auto-generated method stub
//          logger.warn("As the Redis Cache server may be down. Unable to evict cache..." );
//      }
//      
//      @Override
//      public void handleCacheClearError(RuntimeException exception, Cache cache) {
//          // TODO Auto-generated method stub
//          logger.warn("As the Redis Cache server may be down. Unable to clear cache..." );
//      }
//  };
//  return cacheErrorHandler;
// }

}

这里是HelloWorldServica.java

@Service
public class HelloWorldService {

    private static final Logger logger = LoggerFactory.getLogger(HelloWorldService.class);

     @Cacheable(value="descCache")
    public String getDesc() {

        logger.debug("getDesc() is executed!");

        return "Gradle + Spring MVC Hello World Example";

    }
     @Cacheable(value="titleCache")
    public String getTitle(String name) {

        logger.debug("getTitle() is executed! $name : {}", name);

        if(StringUtils.isEmpty(name)){
            return "Hello World";
        }else{
            return "Hello " + name;
        }

    }

}

WelcomeController.java

@Controller
public class WelcomeController {

    private final Logger logger = LoggerFactory.getLogger(WelcomeController.class);
    private final HelloWorldService helloWorldService;
    ApplicationContext ctx = null;

   @Autowired
    public WelcomeController(HelloWorldService helloWorldService) {
        this.helloWorldService = helloWorldService;
        ctx = new AnnotationConfigApplicationContext(AppConfig.class);

   }

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String index(Map<String, Object> model) {

        logger.debug("index() is executed!");

        model.put("title", helloWorldService.getTitle(""));
        model.put("msg", helloWorldService.getDesc());

        return "index";
    }

    @RequestMapping(value = "/hello/{name:.+}", method = RequestMethod.GET)
    public ModelAndView hello(@PathVariable("name") String name) {

        logger.debug("hello() is executed - $name {}", name);

        ModelAndView model = new ModelAndView();
        model.setViewName("index");

        model.addObject("title", helloWorldService.getTitle(name));
        model.addObject("msg", helloWorldService.getDesc());

        return model;

    }

    class CustomRedisCacheManager extends RedisCacheManager {
    private static Log logger = LogFactory.getLog(CustomRedisCacheManager.class);
    public CustomRedisCacheManager(RedisTemplate redisTemplate) {
        super(redisTemplate);
    }
    @Override
    public Cache getCache(String name) {
        return new RedisCacheWrapper(super.getCache(name));
    }

    protected static class RedisCacheWrapper implements Cache {
        private final Cache delegate;
        public RedisCacheWrapper(Cache redisCache) {
            logger.debug("Start:RedisCacheWrapper()" );
            UUID transactionId = UUID.randomUUID();
            long startTime = System.currentTimeMillis();
            long stopTime=0;
            long elapsedTime=0;
            Assert.notNull(redisCache, "'delegate' must not be null");
            this.delegate = redisCache;
            stopTime = System.currentTimeMillis();
            elapsedTime = stopTime - startTime;
            logger.info(" transcation_id=" + transactionId + " operation=RedisCacheWrapper" + " status=Completed, execution_time (ms)=" + elapsedTime );
            logger.debug("End:RedisCacheWrapper()" );

        }
        @Override
        public Cache.ValueWrapper get(Object key) {
            logger.debug("As the Redis Cache server may be down. Unable to save Cache..." );
            try {
                delegate.get(key);
            }
            catch (Exception e) {
                try {
                    return handleErrors(e);
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
            return null;
        }
        @Override
        public void put(Object key, Object value) {
            try {
                delegate.put(key, value);
            }
            catch (Exception e) {
                try {
                    handleErrors(e);
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
        }
        @Override
        public String getName() {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public Object getNativeCache() {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public <T> T get(Object key, Class<T> type) {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public ValueWrapper putIfAbsent(Object key, Object value) {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public void evict(Object key) {
            // TODO Auto-generated method stub

        }
        @Override
        public void clear() {
            // TODO Auto-generated method stub

        }

        // implement clear(), evict(key), get(key, type), getName(), getNativeCache(), putIfAbsent(key, value) accordingly (delegating to the delegate).
        protected <T> T handleErrors(Exception e) throws Exception {
            UUID transactionId = UUID.randomUUID();
            long startTime = System.currentTimeMillis();
            long stopTime=0;
            long elapsedTime=0;
            logger.debug("Exception Thrown" + e.getMessage() );
            if (e instanceof RuntimeException ) 
            {
                stopTime = System.currentTimeMillis();
                elapsedTime = stopTime - startTime;
                logger.info(" transcation_id=" + transactionId + " operation=Redis Cache" + " status=Redis cahce may be down, return null, cause=" + e.getMessage() + " execution_time=" + elapsedTime );
                return null;
            } else {
                throw e;
            }
//          else if (<something different>) { // act appropriately }
//              else {
//                  throw e;
//              }
//          }
        }

    }

共有1个答案

澹台举
2023-03-14

我的错..我解决了这个问题。我正在从get函数返回null

   class CustomRedisCacheManager extends RedisCacheManager {
    private static Log logger = LogFactory.getLog(CustomRedisCacheManager.class);
    public CustomRedisCacheManager(RedisTemplate redisTemplate) {
        super(redisTemplate);
    }
    @Override
    public Cache getCache(String name) {
        return new RedisCacheWrapper(super.getCache(name));
    }

    protected static class RedisCacheWrapper implements Cache {
        private final Cache delegate;
        public RedisCacheWrapper(Cache redisCache) {
            logger.debug("Start: operation=RedisCacheWrapper" );
            UUID transactionId = UUID.randomUUID();
            long startTime = System.currentTimeMillis();
            long stopTime=0;
            long elapsedTime=0;
            Assert.notNull(redisCache, "'delegate' must not be null");
            this.delegate = redisCache;
            stopTime = System.currentTimeMillis();
            elapsedTime = stopTime - startTime;
            logger.debug(" transcation_id=" + transactionId + " operation=RedisCacheWrapper" + " status=Completed, execution_time (ms)=" + elapsedTime );
            logger.debug("End: operation=RedisCacheWrapper" );

        }
        @Override
        public Cache.ValueWrapper get(Object key) {
            logger.debug("Start: operation=get(Object key)" );

            System.out.println("Start: get(Object key)" );
            try {
                Cache.ValueWrapper valueWrapper=delegate.get(key);
                System.out.println("End: get(Object key) returning valueWrapper" );
                logger.debug("End: operation=get(Object key)" );
                ***return valueWrapper;***
            }
            catch (Exception e) {
                try {
                    return handleErrors(e);
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                    return null;
                }
            }

        }
        @Override
        public void put(Object key, Object value) {
            logger.debug("Start: operation=put" );
            try {
                delegate.put(key, value);
                logger.debug("End: operation=put" );
            }
            catch (Exception e) {
                try {
                    handleErrors(e);
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
        }
        @Override
        public String getName() {
            // TODO Auto-generated method stub
            return delegate.getName();
//          return null;
        }
        @Override
        public Object getNativeCache() {
            // TODO Auto-generated method stub
            return delegate.getNativeCache();

//          return null;
        }
        @Override
        public <T> T get(Object key, Class<T> type) {
            // TODO Auto-generated method stub
            return delegate.get(key, type);
            //return null;
        }
        @Override
        public ValueWrapper putIfAbsent(Object key, Object value) {
            // TODO Auto-generated method stub
            return delegate.putIfAbsent(key, value);
        }
        @Override
        public void evict(Object key) {
            // TODO Auto-generated method stub

            logger.info("Carch is evicted");
        }
        @Override
        public void clear() {
            // TODO Auto-generated method stub
            logger.info("Carch is clear");

        }

        // implement clear(), evict(key), get(key, type), getName(), getNativeCache(), putIfAbsent(key, value) accordingly (delegating to the delegate).
        protected <T> T handleErrors(Exception e) throws Exception {
            logger.debug("Start: operation=handleErrors" );
            UUID transactionId = UUID.randomUUID();
            long startTime = System.currentTimeMillis();
            long stopTime=0;
            long elapsedTime=0;
            logger.debug("Exception Thrown" + e.getMessage() );

            if (e instanceof RuntimeException ) 
            {
                stopTime = System.currentTimeMillis();
                elapsedTime = stopTime - startTime;
                logger.debug(" transcation_id=" + transactionId + " operation=handleErrors" + " status=Redis cahce may be down, return null, cause=" + e.getMessage() + " execution_time=" + elapsedTime );
                return null;
            } else {
                logger.debug(" transcation_id=" + transactionId + " operation=handleErrors" + " status=Redis cahce may be down, Some Other exception, cause=" + e.getMessage() + " execution_time=" + elapsedTime );
                throw e;
            }
//          else if (<something different>) { // act appropriately }
//              else {
//                  throw e;
//              }
//          }
        }

    }
}
 类似资料:
  • 问题内容: 我正在阅读揭露java.lang.Out OfMemoryError,我想知道我是否正确理解它。的确,如果Java VM抛出 :请求的阵列大小超出VM限制 这意味着VM拒绝了数组的创建,因为它已经超出了预定义的限制(超出了VM的限制),而 不是 因为我的堆空间用完了吗? 我是否可以说这并不表示记忆不足? 即使我有 无限的 记忆 无处不在 ,Java虚拟机仍然可以抛出,如果它不喜欢我的请

  • 问题内容: 我有一个包含10个元素的div,这些元素将被逐个更新,延迟时间为2秒。下面是相同的代码 但是,当我运行它时,所有元素都会一起更新。该程序只是添加一个延迟添加一个开始,并且所有元素都一起更新(被标记)。如何制作代码来逐一标记元素? 问题答案: 您正在打破React的两个基本规则: 不要直接改变状态 如果根据现有状态更新状态,请使用回调形式,因为状态更新可能是异步的(无论如何,在您的示例中

  • 我使用CORS请求将数据发布到不同域上的php脚本。我收到错误: 跨域请求被阻止:同源策略不允许读取“mydomain”处的远程资源(原因:缺少CORS标头“Access-Control-Allow-Origin”)。 我已经使用以下代码在php中设置了标题。 我也在这篇文章中尝试了这个代码 这是供参考的javascript代码 响应标题 请求标头 但我运气不好任何帮助我都很感激

  • 问题内容: 我正在学习如何在Android中使用线程,并且为此,我制作了一个播放一系列笔记的小型应用程序。这个想法是,有一个开始按钮和一个结束按钮,(显然)如果您按下开始按钮,它将开始播放音乐,而如果您按下结束按钮,它将停止播放。开始按钮可以正常工作,但是问题是结束按钮不能正常工作。我在找出原因时遇到了麻烦,因此也许有些人可以帮助我。这是代码: 问题答案: 您正在调用正在播放的线程,但此时可能正在

  • 问题内容: 我有一个带有2个表的MySql数据库: 国家是公正的。 结果是a ,a和a 。 并非所有国家/地区在每个日期都有结果。 如何创建一个查询,列出所有国家及其特定结果,但仍然列出它们,并且如果结果表上没有结果,则显示0? 问题答案: 在两个表之间使用LEFT JOIN 要显示0(对于该列),如果没有结果,请使用IFNULL。