今天一个程序,关闭 jedis 时报错 JedisException:Could not return the resource to the pool 。。。IllegalStateException: Invalidated object not currently part of this pool
关闭 jedis 是这样写的:
@Autowired
private RedisUtil redisUtil;
Jedis jedis = redisUtil.getJedis();
。。。
} finally {
if ( jedis != null ) {
jedis.close(); // 报错
}
}
网上说是多线程创建 jedisPool 导致的问题,参考:
https://my.oschina.net/zhuguowei/blog/406807
http://bert82503.iteye.com/blog/2184225
http://www.voidcn.com/article/p-esrbxogl-dr.html
http://code.taobao.org/p/moonx/diff/6/trunk/springside4/modules/redis/src/main/java/org/springside/modules/nosql
解决方法,在 redisUtil 里加上这三个方法:
// 关闭 jedis
public void closeJedis( Jedis jedis ) {
try {
if ( jedis != null ) {
if ( jedis != null ) {
jedis.close();
}
}
} catch (Exception e) {
closeBrokenResource( jedis );
}
}
/**
* Return jedis connection to the pool, call different return methods depends on whether the connection is broken
*/
public void closeBrokenResource( Jedis jedis ) {
try {
jedisPool.returnBrokenResource( jedis );
} catch ( Exception e ) {
destroyJedis( jedis );
}
}
/**
* 在 Jedis Pool 以外强行销毁 Jedis
*/
public static void destroyJedis( Jedis jedis ) {
if ( jedis != null ) {
try {
jedis.quit();
} catch ( Exception e ) {
print( ">>> RedisUtil-jedis.quit() : " + e );
//e.printStackTrace();
}
try {
jedis.disconnect();
} catch ( Exception e ) {
print( ">>> RedisUtil-jedis.disconnect() : " + e );
//e.printStackTrace();
}
}
}
然后,在程序里,不用 jedis.close() 关闭 jedis,而是调用注入的 redisUtil 的 closeJedis( jedis ) 方法:
} finally {
redisUtil.closeJedis( jedis );
}
-----------------------------
2018-6-23 上午 修改了一下 destroyJedis( Jedis jedis ) 这个方法
-----------------------------
修改完这个关闭方法后,还出现了一次这个报错 JedisException:Could not return the resource to the pool
网上继续搜,发现
1 - 要增大 jedisPool 的连接数
maxTotal=1200
maxWaitMillis=3000
maxIdle=400
timeout=3000
config.setMaxTotal( maxTotal );
config.setMaxIdle( maxIdle );
config.setMaxWaitMillis( maxWaitMillis );
config.setTestOnBorrow( true );
2 - 增加 jedisPool 其他几个参数设置
// 在还回 jedis pool 时,是否提前进行 validate 操作
config.setTestOnReturn( false );
// idle 时进行连接扫描
config.setTestWhileIdle( true );
// 表示 idle object evitor 两次扫描之间要sleep的毫秒数
config.setTimeBetweenEvictionRunsMillis( 30000 );
// 表示 idle object evitor 每次扫描的最多的对象数
config.setNumTestsPerEvictionRun( 10 );
// 表示一个对象至少停留在 idle 状态的最短时间,然后才能被 idle object evitor 扫描并驱逐;这一项只有在 timeBetweenEvictionRunsMillis 大于 0 时才有意义
config.setMinEvictableIdleTimeMillis( 60000 );
3 - 注意代码里操作完 redis 要关闭 redis 连接。
这样再获取 redis 连接时就不再报错了。
------------------------
又报错了。网上说,还要在 getJedis 里捕获异常并处理
public Jedis getJedis() {
Jedis jedis = null;
try {
if ( jedisPool != null ) {
jedis = jedisPool.getResource();
return jedis;
} else {
System.out.println( "RedisUtil-getJedis() : jedisPool is null. getJedis() return null" );
return null;
}
} catch ( Exception e ) {
if ( jedis != null ) {
// 获取连接失败时,应该返回给 jedisPool, 否则每次发生异常将导致一个 jedis 对象没有被回收
jedisPool.returnBrokenResource( jedis );
}
System.out.println( "RedisUtil-getJedis() : " + e );
e.printStackTrace();
return null;
}
}
---------------------------------
2018-7-29
发现 redisUtil 还会报错 Timeout waiting for idle object。
网上人说,要在 finally 里关闭 jedis 连接。参考
blog.csdn.net/qq_35952082/article/details/52672570
---- 检查自己的应用程序是否正确关闭了数据库连接,注意一定要放到 finally 中关闭
blog.csdn.net/gfw589/article/details/53674087
---- 放到 finally
我照着改了,在 finally 里关闭 jedis 连接。。项目运行一段时间还是报错 Timeout waiting for idle object
又搜到了查看 redis 连接数的方法
String info = jedis.info(); // 用 info 命令查看 redis 的连接数
println( info ); // connected_clients 就是 redis 连接数
发现,项目运行起来后,redis 的连接数在不断上涨!
后来检查代码,有一些地方操作完 redis ,之后有一些 thread.sleep 这样的操作,在方法的结尾才去关闭 jedis 连接 closeJedis。
改成了:操作完 redis ,下一行代码就关闭 jedis 连接。这样再查看项目的 redis 连接数,它就不再不断上涨了