【解决】com.mysql.cj.jdbc.Driver failed to unregister it /Abandoned connection cleanup thread

错误:

16-May-2018 19:34:22.638 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [ziyue] registered the JDBC driver * [com.mysql.cj.jdbc.Driver] but failed to unregister it when the web application was stopped.* To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
16-May-2018 19:34:22.639 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ziyue] appears to have started a thread named* [Abandoned connection cleanup thread] but has failed to stop it. * This is very likely to create a memory leak. Stack trace of thread:
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:70)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)

   在搭建的SSM框架(使用DBCP连接池)中,在关闭Tomcat9.0的时候报出如下错误,虽然只是两个警告,但是总是非常不爽的。
   通过这个报错就可以看出在关闭Tomcat的时候,有两个资源没有释放导致的警告。所以如下通过释放这两个资源的解决办法。两个资源通过包名就可以知道是与数据库连接有关的资源,百度了一番,最终找到了解决方法。

解决:
   解法1.添加一个XBasicDataSource类继承自BasicDataSource,并重写其close()方法
    重点:在消除BUG的过程中,才发现这是DBCP连接池的一个BUG,我这里也是使用的官网给出的修复—-官网错误报告


import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread;
import org.apache.commons.dbcp2.BasicDataSource;

import java.sql.DriverManager;
import java.sql.SQLException;

public class XBasicDataSource extends BasicDataSource {
    @Override
    public synchronized void close() throws SQLException {
    //以下两句代码分别对应两个资源的关闭
        DriverManager.deregisterDriver(DriverManager.getDriver(getUrl()));
        AbandonedConnectionCleanupThread.checkedShutdown();
        super.close();
    }
}

   BasicDataSource是配置DBCP连接池的类,为了使用我们刚才的close()方法,此处的class需要使用我们刚写的XBasicDataSource 类

<--<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
          destroy-method="close">此处是未重写之前的配置类-->

<bean id="dataSource" class="com.ziyue.listener.XBasicDataSource"
          destroy-method="close">
        <property name="driverClassName" value="${driver}" />
        <property name="url" value="${url}" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="${initialSize}"/>
        <!-- 连接池最大数量 -->
        <property name="maxTotal" value="${maxActive}"/>
        <!-- 连接池最大空闲 -->
        <property name="maxIdle" value="${maxIdle}"/>
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="${minIdle}"/>
        <!-- 获取连接最大等待时间 -->
        <property name="maxWaitMillis" value="${maxWait}"/>
    </bean>

   解法2.由于以上问题出现在Tomcat关闭的时候,也就是Web应用结束的时候,所以我们可以利用Web的监听器在Web应用关闭的时候注销这两个资源,同样,实现的监听器MyServletContextListener 实现ServletContextListener接口并重写contextDestroyed()方法

package com.ziyue.listener;


import com.mysql.cj.jdbc.AbandonedConnectionCleanupThread;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

//修复DBCP的BUG,https://issues.apache.org/jira/browse/DBCP-332
public class MyServletContextListener implements ServletContextListener{

             @Override
             public void contextInitialized(ServletContextEvent servletContextEvent) {

             }

             @Override
             public void contextDestroyed(ServletContextEvent servletContextEvent) {
             //这里如果Web应用拥有多个数据库的连接,可以一并关闭
                 Enumeration<Driver> drivers = DriverManager.getDrivers();
                 Driver driver = null;
                 while (drivers.hasMoreElements()) {
                     try {
                         driver = drivers.nextElement();
                         DriverManager.deregisterDriver(driver);
                     } catch (SQLException ex) {
                     }
                 }
                 AbandonedConnectionCleanupThread.checkedShutdown();
             }
         }

   完成了监听器的编写,还需要在web.xml中配置为监听器才会在项目启动和关闭时候分别调用它的两个方法

 <--ServletContext监听器--> 
  <listener>
    <listener-class>com.ziyue.listener.MyServletContextListener</listener-class>
  </listener>

  虽然上面两种方法都可以实现资源的关闭,不过既然属于数据库的相关资源,还是建议在数据库相关的类中去释放它们,这也符合各个组件各司其职的规矩,毕竟这也是DBCP官方给出的修复方案。

猜你喜欢

转载自blog.csdn.net/qq_32483145/article/details/80341920
今日推荐