多线程环境下Spring-Data-Redis集成Jedis遇类型转换异常求助
你碰到的这个ClassCastException: [B cannot be cast to java.lang.Long异常,是调用rPush操作时触发的,结合你的环境配置和代码,我来帮你定位问题并给出可行的解决方案。
你的环境信息
- Jedis版本:2.9.0
- Spring-Data-Redis版本:1.8.12.RELEASE
- Redis服务器版本:3.0.6
异常根源分析
从栈信息里的redis.clients.jedis.Connection.getIntegerReply(Connection.java:265)可以看出,Jedis试图把Redis返回的二进制数据([B就是byte数组)转换成Long类型时失败了。结合多线程场景,主要有两个核心原因:
- 连接池复用导致的响应污染:JedisPool是连接复用机制,多线程下如果某个线程没处理完之前的命令响应,或者连接归还池时没清理干净状态,后续线程复用这个连接执行
rPush时,可能读到上一个命令遗留的二进制响应——而rPush本来应该返回Long类型的列表长度,自然就会触发类型转换错误。 - Redis key的类型不匹配:如果你执行
rPush的key在Redis中不是list类型(比如是string),执行rPush会返回错误,但客户端序列化层可能把错误响应转换成了byte数组,最终导致类型转换异常。
具体解决方案
方案1:优化连接池配置,避免脏连接复用
调整你的JedisPoolConfig,增加归还连接时的有效性检查,确保脏连接不会被复用:
jedisPoolConfig.setTestOnReturn(true); // 新增这行 jedisPoolConfig.setTestOnBorrow(true); // 你已有的配置
另外,如果你在代码中手动获取过JedisConnection(比如直接调用jedisConnectionFactory.getConnection()),一定要在finally块中关闭连接,避免连接状态残留:
JedisConnection conn = null; try { conn = jedisConnectionFactory.getConnection(); // 执行Redis操作 } finally { if (conn != null) { conn.close(); } }
注:你的RedisTemplate本身会自动管理连接,但开启了事务支持,要确保事务使用流程正确,避免连接被长时间占用。
方案2:检查Redis中目标key的类型
登录Redis服务器,用TYPE命令检查你执行rPush的key类型:
redis-cli TYPE your-target-key
如果返回的不是list,说明这个key之前被用其他类型的命令操作过(比如SET),需要先删除该key:
redis-cli DEL your-target-key
之后再执行rPush操作,就能保证类型一致了。
方案3:升级版本修复兼容性bug
你当前使用的Spring-Data-Redis 1.8.12.RELEASE和Jedis 2.9.0虽然理论兼容,但该版本分支存在一些连接复用相关的已知小bug。可以尝试升级到同分支的稳定版:
- 将Spring-Data-Redis升级到
1.8.23.RELEASE(1.8.x分支最新稳定版) - 将Jedis升级到
2.9.3(2.9.x分支最新稳定版)
方案4:排查事务支持的影响
你开启了redisTemplate.setEnableTransactionSupport(true),多线程下如果事务使用不当,可能导致连接状态异常。可以暂时关闭事务支持,观察异常是否消失,以此排查是否是事务导致的问题:
redisTemplate.setEnableTransactionSupport(false);
内容的提问来源于stack exchange,提问作者zhaokun




