我使用的是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;
// }
// }
}
}
我的错..我解决了这个问题。我正在从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。