欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Druid connection holder is null autoReconnect=true

程序员文章站 2022-06-14 08:06:17
...

问题说明:

在开发spring整合druid链接池(1.0.2版本)的项目时,出现tomcat容器每天早上必须重启一次,否在链接池无法正常使用,其中错误日志如下所示:

 

### Cause: java.sql.SQLException: connection holder is null
; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; connection holder is null; nested exception is java.sql.SQLException: connection holder is null
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:71)
........
Caused by: java.sql.SQLException: connection holder is null
	at com.alibaba.druid.pool.DruidPooledConnection.checkState(DruidPooledConnection.java:1083)
	at com.alibaba.druid.pool.DruidPooledConnection.getAutoCommit(DruidPooledConnection.java:698)
.....
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 44,982,301 milliseconds ago.  The last packet sent successfully to the server was 44,982,338 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

 

在网上找到一些的解决方式具体如下所示:

http://blog.csdn.net/ayanami001/article/details/48181243

http://blog.csdn.net/wo8553456/article/details/40396401

通过以上博客的说明等资料,我的druid的连接池配置信息如下所示:

 

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">   
    <!-- 基本属性 url、user、password -->  
    <property name="url" value="${jdbc.url};autoReconnect=true" />  
    <property name="username" value="${jdbc.user}" />  
    <property name="password" value="${jdbc.password}" />  
    <!-- 配置初始化大小、最小、最大 -->  
    <property name="initialSize" value="1" />  
    <property name="minIdle" value="1" />   
    <property name="maxActive" value="20" />  
    <!-- 配置获取连接等待超时的时间 -->  
    <property name="maxWait" value="60000" />  
   
    <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->  
    <property name="timeBetweenEvictionRunsMillis" value="60000" />  
   
    <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->  
    <property name="minEvictableIdleTimeMillis" value="300000" />  
    
    <property name="validationQuery" value="SELECT 'x'" />  
	<!-- 申请连接的时候检测,如果空闲时间大于 timeBetweenEvictionRunsMillis, 执行validationQuery检测链接是否有效-->
    <property name="testWhileIdle" value="true" />  
	<!-- 申请连接的时候检测,执行validationQuery检测链接是否有效-->
    <property name="testOnBorrow" value="false" />  
	<!-- 返还连接的时候检测,执行validationQuery检测链接是否有效-->
    <property name="testOnReturn" value="false" />  
   
    <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->  
    <property name="poolPreparedStatements" value="true" />  
    <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />  
   
    <!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->  
    <property name="filters" value="stat" />
    
    <!-- 打开removeAbandoned 开关,对于建立时间超过removeAbandonedTimeout的连接强制关闭-->  
    <property name="removeAbandoned" value="true" />
    <!-- 为removeAbandonedTimeoutMillis(默认300*1000)设置值,与 removeAbandoned 关联使用配置指定连接建立多长时间就需要被强制关闭,此时(1800*1000)-->  
    <property name="removeAbandonedTimeout" value="1800" />  
	
</bean>

 更多更完善配置解释可详见:http://blog.csdn.net/supingemail/article/details/50809982

在原有druid连接池配置上添加了一下配置:

.....
<!-- autoReconnect=true -->
<property name="url" value="${jdbc.url};autoReconnect=true" />  
.....
<!-- 打开removeAbandoned 开关,对于建立时间超过removeAbandonedTimeout的连接强制关闭-->  
	<property name="removeAbandoned" value="true" />
	<!-- 为removeAbandonedTimeoutMillis(默认300*1000)设置值,与 removeAbandoned 关联使用配置指定连接建立多长时间就需要被强制关闭,此时(1800*1000)-->  
    <property name="removeAbandonedTimeout" value="1800" />  
...

 通过配置后,发现依旧无法解决connection holder is null 错误信息,每天依旧需要重启解决。

于是通过断点调试,发现所有druid的配置均已生效,问题依旧未解决。

 

通过以上的尝试,猜测问题可能存在于代码中,并非时druid的配置导致的错误的产生,分析前后跟数据库链接池打交道的无非是事务,于是针对项目中的事务应用进行了排查,问题终于浮出水面:

 

由于该链接池使用的是如下方式定义的事务,在项目中手动配置事务使用,代码如下所示:

//定义事务
<bean id="dataSourceManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>


//引入事务  DataSourceTransactionManager 为 PlatformTransactionManager 子类
@Service
public class RedpackageStockManagerImpl {	
   @Autowired
    private PlatformTransactionManager dataSourceManager;
	...
}

 

上面代码单独出现无任何问题,问题就在于该项目中并非有只有一个数据库链接池,另一个数据库链接池也同样定义了一个 DataSourceTransactionManager事务管理器,而在使用@Autowired进行事务管理引入时是使用的根据类型进行引入,因此在通过事务使用dataSource链接池时,就会出现事务被错用现象,从而导致数据库链接池中的链接被非正常关闭,再下次再次使用时出现connection holder is null 错误,修改方法如下所示:

 

@Service
public class RedpackageStockManagerImpl {	
    @Resource(name = "dataSourceManager")
    private PlatformTransactionManager dataSourceManager;
	...
}

 

最后使用@Resource注解根据名称(dataSourceManager)依赖注入事务管理器,成功解决connection holder is null ,告别重启!