使用Jedis操作Redis数据库时Could not return the resource to the pool

项目背景

事情经过是这样的..........
我负责的项目又改了需求(难受 -_-),实现起来要在用户登录后存入缓存的数据中添加一项数据对用户进行标记,然而我加了这个字段之后测试就会报错(那肯定就是这个字段的问题啦~)

Java报错是这个样子的

redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
    at redis.clients.util.Pool.returnBrokenResourceObject(Pool.java:103)
    at redis.clients.jedis.JedisPool.returnBrokenResource(JedisPool.java:239)
    at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:255)
    at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:16)
    at org.springframework.data.redis.connection.jedis.JedisConnection.close(JedisConnection.java:257)
    at org.springframework.data.redis.core.RedisConnectionUtils.releaseConnection(RedisConnectionUtils.java:206)
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:205)
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:153)
    at org.springframework.data.redis.cache.RedisCache.put(RedisCache.java:140)
    at org.springframework.data.redis.cache.RedisCache.put(RedisCache.java:125)
    at org.springframework.cache.interceptor.AbstractCacheInvoker.doPut(AbstractCacheInvoker.java:82)
    at org.springframework.cache.interceptor.CacheAspectSupport$CachePutRequest.apply(CacheAspectSupport.java:651)
    at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:358)
    at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:299)
    at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)

报错倒是很简单,在使用Jedis之后不能正常释放这个Jedis资源,我们在使用一个Jedis资源之后如果不能把它放回Redis连接池,后续其他缓存操作就会创建新的连接,而我们这个没有正常释放的Jedis会一直被占用。

我的代码是这样的

        //缓存session对应的用户
        String redisPrefix = RedisPrefix.getSessionKey(session);
        Map<String ,String> userInfo = new HashMap<>();
        userInfo.put("userId", userId);
        userInfo.put("pid", pid);
        userInfo.put("channelUid", openId);
        userInfo.put("BindUser", bindUid); //这个是我新加的
        log.info("redis_key: "+redisPrefix+" ||userInfo: "+userInfo);

        RedisUtil.hmsetex(CommonConfig.REDIS_DB, redisPrefix, userInfo, CommonConfig.SESSION_EXPIREDTIME);
        log.info("save session");

RedisUtil.hmsetex方法

    public static String hmsetex(int db, String key, Map<String, String> value, int seconds) {
        Jedis jedis = null;
        String result = null;
        try {
            jedis = getJedis();
            if(jedis != null) {
                jedis.select(db);
                result = jedis.hmset(key, value);
                jedis.expire(key, seconds);
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            returnResource(jedis);
            return result;
        } finally {
            returnResource(jedis);
        }
    }

释放资源

    public static void returnResource(final Jedis jedis) {
        if (jedis != null) {
            jedis.close();
            //jedisPool.returnResource(jedis);
        }
    }

jedis的close方法在Java源码中可以找到,就是正常的释放资源,这里就不再贴出来了。

在网上看了诸多解决方法,然而并不对症,但是却提醒了我错误所在。有一篇文章分析原因是Jedis关闭了两次,第二次关闭的时候因为这个Jedis实例已经不存在了,所以无法把它放回连接池。我新加参数bindUid是从数据库中获取的,如果数据库中这个值为null,那么这里存入缓存的时候这个值也是null,所以我猜测很有可能这里报错导致Jedis异常关闭,之后调用returnResource的时候二次关闭导致报错。

为了证实这个猜测,我在本地起了一个Redis,自己测试结果如下

127.0.0.1:6379> hset search baidu "BAIDU"
(integer) 1
127.0.0.1:6379> hset search google "GOOGLE"
(integer) 1
127.0.0.1:6379> hgetall search
1) "baidu"
2) "BAIDU"
3) "google"
4) "GOOGLE"
127.0.0.1:6379> hset search sougou
(error) ERR wrong number of arguments for 'hset' command

可以看到当插入数据sougou的时候因为value是null,所以会出现报错,之后确认数据也没存入Redis,然后我又测试了其他几种存入方式

127.0.0.1:6379> hset search 360 null
(integer) 1
127.0.0.1:6379> hset search yahoo ""
(integer) 1
127.0.0.1:6379> hgetall search
1) "baidu"
2) "BAIDU"
3) "google"
4) "GOOGLE"
5) "360"
6) "null"
7) "yahoo"
8) ""

当我们存入360的value为null的时候,值并不是nil而是一个字符串"null",同样的,我存入值为nil的时候实际并不是空,而是字符串的"nil"。由此可得知使用Jedis操作Redis的时候并不支持存入空值,如果想要存入空值应该存入一个空字符串,所以我把我的代码改成了如下的样子

        //缓存session对应的用户
        String redisPrefix = RedisPrefix.getSessionKey(session);
        Map<String ,String> userInfo = new HashMap<>();
        userInfo.put("userId", userId);
        userInfo.put("pid", pid);
        userInfo.put("channelUid", openId);
        userInfo.put("BindUser", bindUid == null ? "" : bindUid); //进行判断,存入值
        log.info("redis_key: "+redisPrefix+" ||userInfo: "+userInfo);

        RedisUtil.hmsetex(CommonConfig.REDIS_DB, redisPrefix, userInfo, CommonConfig.SESSION_EXPIREDTIME);
        log.info("save session");

然后就不会报Could not return the resource to the pool了~~~


这里只是给大家提供另一种思路,如果你检查了你的Redis连接没有问题,而且之前的代码逻辑可以正常释放Jedis资源,那么你可以按照我的思路去检查下存入的value有没有可能是null
目前只发现Jedis会出现这种情况,Redistemplate还没有发现这种情况

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 1 Redis介绍1.1 什么是NoSql为了解决高并发、高可扩展、高可用、大数据存储问题而产生的数据库解决方...
    克鲁德李阅读 5,171评论 0 36
  • redis是一个以key-value存储的非关系型数据库。有五种数据类型,string、hashes、list、s...
    林ze宏阅读 962评论 0 0
  • 【本教程目录】 1.redis是什么2.redis的作者3.谁在使用redis4.学会安装redis5.学会启动r...
    徐猿猿阅读 1,857评论 0 35
  • 文章已经放到github上 ,如果对您有帮助 请给个star[https://github.com/qqxuanl...
    尼尔君阅读 2,228评论 0 22
  • 5月9日, 三三八处第一、第二党支部一并进行了主题党日十活动。以“凝心聚力促发展,协同创新”为主题,对行政区...
    陈玉军_c53a阅读 229评论 0 0