druid连接池异常


在从excel导入10W条数据到mysql中时,运行一段时间就会抛这个异常,连接池问题

org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is org.hibernate.TransactionException: JDBC begin failed:
Caused by: java.sql.SQLException: connection holder is null
	at com.alibaba.druid.pool.DruidPooledConnection.checkState(DruidPooledConnection.java:1085)
	at com.alibaba.druid.pool.DruidPooledConnection.getMetaData(DruidPooledConnection.java:825)
	at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:285)

找了下解决方案
1.

给jdbc url 增加 autoReconnect=true 一定能解决你的问题,可以定期观察一下 show processlist
改进方法如下:
<property name="url" value="jdbc:mysql://localhost/数据库实例名称?&useUnicode=true&characterEncoding=utf-8&autoReconnect=true"/>

2.

寻找支持重连的连接池。
           注意:c3p0连接池支持重连;重连参数是:
               idleConnectionTestPeriod   设置空闲连接测试周期
               preferredTestQuery : 设置一查询语句,用于重连测试
              testConnectionOnCheckin设置为true
              testConnectionOnCheckout设置为true

在sessionFactory里配置:

<property name="hibernateProperties">
   <props>

        <prop key="hibernate.autoReconnect">true</prop>

  </props>
</property>
这两种不同的配置都是使连接池自动重连

后面发现问题还是存在

通过研究源码我可以确定"Druid提供的getConnection()或者getConnection(long maxWaitMillis)方法不能保证在同一个线程中获取的始终是一个连接,直到显示的将连接关闭吗?"。必须在程序在缓存从Druid中取出的连接才能保证现一个事务在使用的是同一个连接。

而抛出“connection holder is null”异常的原因可能在于:

关闭长时间不使用的连接超时时间,单位秒
removeAbandonedTimeout

假设这个参数的值 为30分钟,当一个连接在获取后30分钟还没释放,也就是Connection的DruidPooledPreparedStatement对象执行完了executXXX()方法但还未执行close、commit、rollback方法,对应于Connection的running参数的值为false,这时Durid的DestroyConnectionThread线程会自动将该连接回收。当程序要commit()连接时会执行checkState()方法,这个方法会执行以下代码:

if (holder == null) {  
 if (disableError != null) {  
   throw new SQLException("connection holder is null", disableError);  
    } else {  
   throw new SQLException("connection holder is null");  
    }  
} 


这段代码就是我们看到的“connection holder is null”异常的来源,因此,我们需要做的就是根据Druid提供的监控信息(主要看“连接持有时间分布”的值)修改这个参数的值,它的值一定要比最长的连接持有时间还要大。

最后我把链接自动清除配置关闭解决了问题
removeAbandoned=false
如果把这个时间调整大一点应该也是可以的
removeAbandonedTimeout=1800

猜你喜欢

转载自qiaoyihang.iteye.com/blog/2321858