其他
老弟:使用Druid数据源遇到“connection holder is null”,怎么办?
系统中出现过几次connection holder is null问题,有的已解决,有的未解决,记录如下。
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秒没还就强制回收,这样就会报上面的错误了。关注公众号Java面试那些事儿,回复关键字面试,获取最新面试题。
建议在生产环境关闭remove abandoned功能,如果数据库负载不重的话,可以开启testOnBorrow。testWhileIde不建议开,因为并发请求多的话,数组后面的连接都不是idle状态,开没开testWhileIdle没啥区别。
第二次系统中有的事务长时间未提交,DBA会把这个连接kill掉,后面请求会报conneciton holder is null
为什么有长时间未提交的事务,这个问题还没找到原因,从Mysql的innodb_trx和lock表里没看到有价值线索,后面想跟踪事务和连接来看看有没有收获。
连接被kill了,应用端会报这样的异常:
来源 | https://www.jianshu.com/p/073daa6b1a37
往期推荐
🔗
领英宣布裁员 960 人:疫情导致企业暂停招聘 你用过Mybatis的动态SQL后,就知道写SQL有多爽了! 什么是a站、b站、c站、d站、e站、f站、g站、h站、i站、j站、k站、l站、m站、n站…z站?
点击阅读原文,获得免费编程资料