Spring Redis错误句柄

 mobiledu2502938445 发布于 2022-12-19 19:23

我在新项目中使用Spring + Redis作为缓存组件.spring config xml文件是:

 




    
    
        
    
      
        
     





用法是

    @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()
    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)无法连接(可能是崩溃或网络未启动),它应该直接连接到数据库并获取数据.

1 个回答
  • 我遇到了同样的问题.我正在开发一些针对数据库的数据服务,通过Spring Caching注释将Redis用作缓存存储.如果Redis服务器变得不可用,我希望服务继续像未缓存一样运行,而不是抛出异常.

    起初我尝试了一个自定义的CacheErrorHandler,这是Spring提供的一种机制.它没有用,因为它只处理RuntimeExceptions,但仍然让像java.net.ConnectException这样的东西搞砸了.

    最后我做的是扩展RedisTemplate,覆盖一些execute()方法,以便它们记录警告而不是传播异常.这看起来有点像黑客,我可能已经覆盖了太少的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;
            }
        }
    }
    

    2022-12-19 19:26 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有