Druid connection holder is null 未解之谜
来源 | https://www.jianshu.com/p/073daa6b1a37
DruidPooledConnection是一个静态代理,持有ConnectionHolder, connection Holder里持有具体的connection对象, 在执行druidPooledConnection的所有和数据库相关方法时,都会先调用checkState()判断connection holder是否为null,如果是null就抛connection holder is null的异常。 那connection holder是什么时候赋值以及什么时候置成null的?
在Datasource.getConnection()获取连接的时候,是从池里取出缓存的connection holder对象,druid是用一个数组缓存connection holder对象,每次都是从最后一个取,还的时候也是放到最后,这样保证位于数组最后的连接会经常处于使用状态,当然这中间会有锁的使用以及池里没线程了通知任务线程去创建新连接。
Datasource.getConnection()从池里拿出connection holder后,然后new一个druidPooledConnection去包装connection holder,所有每次看到都是不同的druidPooledConnection对象。
第一次:系统中事务执行时间过长,超过60秒,后面导致有的请求会报connection holder is null。
拿出来的connection holder肯定不为null,项目中报connection holder is null,说明是在使用过程中connection holder被置成null了,很大概率是被别的线程置成null了,因为本线程只有在事务提交后还连接的时候才置null,在github issue上,作者也反复强调连接不要跨线程使用。而druid真的就有跨线程操作连接的地方,就是remove abandoned connection功能,这个功能是为了回收长时间还没还到池里的连接,多长时间看你设置,而我们项目设置的60秒没还就强制回收,这样就会报上面的错误了。 建议在生产环境关闭remove abandoned功能,如果数据库负载不重的话,可以开启testOnBorrow。testWhileIde不建议开,因为并发请求多的话,数组后面的连接都不是idle状态,开没开testWhileIdle没啥区别。
第二次系统中有的事务长时间未提交,DBA会把这个连接kill掉,后面请求会报conneciton holder is null
为什么有长时间未提交的事务,这个问题还没找到原因,从Mysql的innodb_trx和lock表里没看到有价值线索,后面想跟踪事务和连接来看看有没有收获。 连接被kill了,应用端会报这样的异常:
Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost. com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure. The last packet successfully received from the server was 20,840 milliseconds ago. The last packet sent successfully to the server was 20,840 milliseconds ago. connection holder is null
- 推荐阅读 -
下方二维码关注我
互联网草根,坚持分享技术、创业、产品等心得和总结~
点击“阅读原文”,领取 2020 年最新免费技术资料大全
评论