Java jedis pool的坑

目录

【问题现象】

【问题分析】

【问题原因】

【问题影响】

    1.场景1

    2. 场景2

【解决方法】

【后续】


【问题现象】

       线上问题:业务后台同一个customerId下有两个账号accountId

      1. 产生错误日志:「B cannot cast to java.lang.Long」

      2.  Redis通过key拿到错乱的value值

【问题分析】

      1. JedisConnection是通过JedisPool进行复用的

      2. 异常情况下(如Socket超时等),由于未正确关闭问题连接,将会导致下次Redis请求复用了有问题的Connection

【问题原因】

      jedis的错误使用,问题代码如下:

     

    经过对代码的深入分析,我们发现问题的关键在于returnResource(jedis)这个操作;因若是网络异常的话,pool.returnResource(jedis)仍能成功执行,即能将其返回到池中(这时jedis并不为                空)。  等网络恢复后,并是多线程环境,导致后续其他某个线程获得了同一个Jedis实例(pool.getResource())。

【问题影响】

    1.场景1

           请求1: 获取redis连接 -> 发送GET("Uid1")指定 -> 网络异常 -> 归还问题连接

          请求2: 复用问题连接 -> 发送INCR指令

          分析:在执行请求1的GET("Uid1")时,网络超时,并未实际发送GET("Uid1") 命令,等执行INCR时,网络已恢复正常,

          并且是同一个jedis实例,于是将之前的GET("Uid1")命令(已在输出流缓存中)一并发送;INCR指令实际返回的

          值是GET("Uid1")的值,两个指令的返回值类型不同,导致了ClassCastException,将会触发问题1,

          即类型转换失败「B cannot cast to java.lang.Long

    2. 场景2

          请求1:获取连接 -> 发送GET("Uid1")指定 -> 网络异常 -> 归还问题连接

          请求2:复用问题连接 -> 发送GET("Uid2")指令

          分析:  假设 GET("Uid1")的结果是 "12345" ,GET("Uid2")的结果是"7890"

          前后两次发送相同类型指令,GET("Uid2")得到的结果将是"12345",触发问题2,即通过key获取到错乱的value值

【解决方法】

         推荐的Jedis使用方式,try-catch-finally代码块,catch捕获连接异常,finally里returnBrokenResource,代码如下:

        

【后续】

 Jedis 3.0 以后(含3.0),Jedis returnBrokenResource returnResource的标准写法

finally {

if (jedis != null) {

jedis.close();

  }
}

 1、redis的使用应该要充分考虑各种异常场景下的异常处理。

 2、对java的jedis使用应该要充分了解returnResource和returnBrokenResource的区别

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值