我正在使用Spring + Redis作为新项目中的缓存组件。spring config xml文件是:
<!-- Jedis Connection --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.ip}" p:port="${redis.port}" p:use-pool="${redis.use-pool}" /> <!-- Redis Template --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> </bean> <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager" c:template-ref="redisTemplate"/> <cache:annotation-driven mode="proxy" proxy-target-class="true" cache-manager="cacheManager" />
用法是
@Cacheable(value = "cacheManager", key="#userId") public User getUser(String userId) { System.out.println("execute=="); return userAdminMapper.getUser(userId); }
我的测试用例是:
@Test public void testCacheUser2() { String id = "test"; User user = userService.getUser(id); System.out.println(user); user.setUserCreateDate(new Date()); userService.updateUser(user); User user2 = userService.getUser(id); System.out.println(user2); User user3 = userService.getUser(id); System.out.println(user3); }
如果Redis服务器正在运行,则代码正在正确运行。但是我的问题是,如果我关闭Redis服务器,它将抛出异常:
org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Connection refused: connect at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:140) at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:229) at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:57) at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:128) at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:91) at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:78) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:177) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:152) at org.springframework.data.redis.cache.RedisCache.get(RedisCache.java:87) at org.springframework.cache.interceptor.CacheAspectSupport.findInCaches(CacheAspectSupport.java:297) at org.springframework.cache.interceptor.CacheAspectSupport.findInAnyCaches(CacheAspectSupport.java:287) at org.springframework.cache.interceptor.CacheAspectSupport.collectPutRequests(CacheAspectSupport.java:266) at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:199) at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:178) at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:60) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644) at sg.infolab.common.admin.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$c7f982a7.getUser(<generated>) at sg.infolab.admin.test.RedisServiceTest.testCacheUser2(RedisServiceTest.java:35) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Connection refused: connect at redis.clients.jedis.Connection.connect(Connection.java:150) at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:71) at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.java:1783) at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:137) ... 50 more Caused by: java.net.ConnectException: Connection refused: connect at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351) at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366) at java.net.Socket.connect(Socket.java:529) at redis.clients.jedis.Connection.connect(Connection.java:144) ... 53 more
我想问一下客户端是否无法连接Redis Server,为什么会抛出异常?我们可以配置这样的方案吗?-如果缓存层(Redis Server)无法连接(可能是崩溃或网络未启动),它应该直接连接到数据库并获取数据。
我有同样的问题。我正在通过Spring Caching注释将Redis用作缓存存储区,从而针对数据库开发一些数据服务。如果Redis服务器不可用,我希望这些服务能够像未缓存一样继续运行,而不是抛出异常。
最初,我尝试了一个自定义的CacheErrorHandler,这是Spring提供的一种机制。它并不是很有效,因为它只处理RuntimeExceptions,并且仍然让java.net.ConnectException之类的东西炸毁。
最后,我所做的是扩展RedisTemplate,覆盖了一些execute()方法,以便它们记录警告而不是传播异常。似乎有点hack,我可能重写了太少的execute()方法或太多了,但是在我所有的测试用例中,它都像一个魅力。
但是,此方法有一个重要的操作方面。如果Redis服务器不可用,则必须刷新它(清除条目),然后才能再次使用它。否则,由于同时发生更新,您可能会开始检索数据不正确的缓存条目。
以下是来源。随意使用它。希望对您有所帮助。
import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.SessionCallback; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.data.redis.serializer.RedisSerializer; /** * An extension of RedisTemplate that logs exceptions instead of letting them propagate. * If the Redis server is unavailable, cache operations are always a "miss" and data is fetched from the database. */ public class LoggingRedisTemplate<K, V> extends RedisTemplate<K, V> { private static final Logger logger = LoggerFactory.getLogger(LoggingRedisTemplate.class); @Override public <T> T execute(final RedisCallback<T> action, final boolean exposeConnection, final boolean pipeline) { try { return super.execute(action, exposeConnection, pipeline); } catch(final Throwable t) { logger.warn("Error executing cache operation: {}", t.getMessage()); return null; } } @Override public <T> T execute(final RedisScript<T> script, final List<K> keys, final Object... args) { try { return super.execute(script, keys, args); } catch(final Throwable t) { logger.warn("Error executing cache operation: {}", t.getMessage()); return null; } } @Override public <T> T execute(final RedisScript<T> script, final RedisSerializer<?> argsSerializer, final RedisSerializer<T> resultSerializer, final List<K> keys, final Object... args) { try { return super.execute(script, argsSerializer, resultSerializer, keys, args); } catch(final Throwable t) { logger.warn("Error executing cache operation: {}", t.getMessage()); return null; } } @Override public <T> T execute(final SessionCallback<T> session) { try { return super.execute(session); } catch(final Throwable t) { logger.warn("Error executing cache operation: {}", t.getMessage()); return null; } } }