Redis

这个是今天发现一个bug:在测试redis并发读写的时候(jedis作为客户端,并使用了连接池),总是报 java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.Long
at redis.clients.jedis.Connection.getIntegerReply(Connection.java:161)
at redis.clients.jedis.Jedis.del(Jedis.java:108)
类似的错误,就是返回值类型和文档上的返回值类型不相符,感觉很不应该;开始怀疑是jedis实现的一个bug,后来发现一个现象,当抛一个超时异常的时候,后面就连续的出现一个类似上面的错误,最后终于发现了问题所在。
原先的代码是这样的:
Java代码 复制代码 收藏代码

public long del(String key) {
long rt = 0L;
Jedis jedis = null;
try {
jedis = getJedis();
rt = jedis.del(key);
}
finally
{
releaseJedisInstance(jedis);
}
return rt;
}

[java] view plaincopy

public long del(String key) {
long rt = 0L;
Jedis jedis = null;
try {
jedis = getJedis();
rt = jedis.del(key);
}
finally
{
releaseJedisInstance(jedis);
}
return rt;
}


这样写貌似OK,但实际上有问题,假设jedis在执行这个命令的时候,因为redis超负荷,jedis可能返回超时的异常,这个时候发生了什么,没有处理这个异常,直接将这个jedis的链接返回到了连接池,这样有没有问题呢?
查看jedis源码发现他的connection中对网络输出流做了一个封装,其中自建了一个buffer,所以当发生异常的时候,这个buffer里还残存着上次没有发送或者发送不完整的命令,这个时候没有做处理,直接将该连接返回到连接池,那么重用该连接执行下次命令的时候,就会将上次没有发送的命令一起发送过去,所以才会出现上面的错误“返回值类型不对”;
所以正确的写法应该是在发送异常的时候,销毁这个连接,不能再重用!
正确的写法如下:
Java代码 复制代码 收藏代码

public long del(String key) {
long rt = 0L;
Jedis jedis = null;
try {
jedis = getJedis();
rt = jedis.del(key);
} catch (Exception e) {
returnBrokenResource(jedis);
}
finally
{
releaseJedisInstance(jedis);
}
return rt;
}

[java] view plaincopy

public long del(String key) {
long rt = 0L;
Jedis jedis = null;
try {
jedis = getJedis();
rt = jedis.del(key);
} catch (Exception e) {
returnBrokenResource(jedis);
}
finally
{
releaseJedisInstance(jedis);
}
return rt;
}


从上面的分析来看,我更认为是jedis实现的一个bug,当连接出现异常的时候,应该对该连接的buffer进行清空的,你认为呢?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值