JedisPool报错:Could not return the resource to the pool

Bug的起源和解法

这个错误来的实在猝不及防,第一次请求可以成功使用JedisPool,而第二次请求便会报错,在翻遍了所有相关博客后一度以为是自己的配置出了错,于是不断修改配置文件中的redis连接池参数。
折腾老半天之后,没有帮助TAT
这时,我想起10年前的某个午后,蝉鸣的空气中传来的几分安定,出神地趴在窗边看麻雀扑腾的我,被一声厉呵带回现实。之后便到了标准环节–”下课到办公室找我”。之后的事情便记不太清了,只是我深深地记得当时的心境,想不出的问题换个角度想,一定会有不同的发现。
那就回归报错吧,“无法将资源返回到池”,再回想到我的jedisPool对象,旷的一声,仿佛天旋地转一般,一切的一切突然都变透彻了。

错误根源及出错原因

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public boolean followUser(Integer localUserId, Integer userId) {
try (Jedis jedis = jedisPool.getResource()) {
jedis.zadd(localUserId + RedisKey.FOLLOW_USER, System.currentTimeMillis(),
String.valueOf(userId));
jedis.zadd(userId + RedisKey.FOLLOWED_USER, System.currentTimeMillis(),
String.valueOf(localUserId));
} catch (JedisException e) {
return false;
}
jedisPool.close();// 问题就出在这里
return true;
}

JedisPool在configuration类中初始化(项目启动时有spring自动扫描)
然而在每个业务类调用完之后就被手动关闭,自然执行完第一次后就不再能取出resource的,也无法return。
解决这个bug只需把每个service实现类中的jedisPool.close()删去即可。

为什么会出现这种写法

说到这个就不得不提起Jedis的wiki
官方po出的demo是这样使用jedis的:

首先引入pom

1
2
3
4
5
6
7
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>

然后实例化JedisPool

1
JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost");

接着实例化jedis有两种方法

  1. try-with-resource法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /// Jedis implements Closeable. Hence, the jedis instance will be auto-closed after the last statement.
    try (Jedis jedis = pool.getResource()) {
    /// ... do stuff here ... for example
    jedis.set("foo", "bar");
    String foobar = jedis.get("foo");
    jedis.zadd("sose", 0, "car"); jedis.zadd("sose", 0, "bike");
    Set<String> sose = jedis.zrange("sose", 0, -1);
    }
    /// ... when closing your application:
    pool.close();// 这便是原罪
  2. 手动关闭jedis法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    Jedis jedis = null;
    try {
    jedis = pool.getResource();
    /// ... do stuff here ... for example
    jedis.set("foo", "bar");
    String foobar = jedis.get("foo");
    jedis.zadd("sose", 0, "car"); jedis.zadd("sose", 0, "bike");
    Set<String> sose = jedis.zrange("sose", 0, -1);
    } finally {
    // You have to close jedis object. If you don't close then
    // it doesn't release back to pool and you can't get a new
    // resource from pool.
    if (jedis != null) {
    jedis.close();
    }
    }
    /// ... when closing your application:
    pool.close();
    虽然不在报错了,但是现在不关的话又不知道在哪能关的了它了。。。

双手奉上: Jedis官方指引