zoukankan      html  css  js  c++  java
  • 【解决】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框架(JDK1.8,使用DBCP和Druid连接池)中,在关闭Tomcat9.0的时候报出如下错误,虽然只是两个警告,但是总是非常不爽的。

       通过这个报错就可以看出在关闭Tomcat的时候,有两个资源没有释放导致的警告。所以如下通过释放这两个资源的解决办法。两个资源通过包名就可以知道是与数据库连接有关的资源,百度了一番,最终找到了解决方法。

    解决:

       解法1.添加一个XBasicDataSource类继承自BasicDataSource,并重写其close()方法
        重点:在消除BUG的过程中,才发现这是DBCP连接池的一个BUG,我这里也是使用的官网给出的修复----官网错误报告。在以后的编程中,我使用阿里的Druid连接池也出现了同样的数据库连接未注销的错误,让我怀疑这究竟是不是连接池的BUG吶?无奈找寻DruidDateSource的关闭数据库连接的方法,没有找到,所以Druid连接池我使用第二种方法解决了。

    
    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官方给出的修复方案。

  • 相关阅读:
    EL表达式
    单例模式
    标准标签JSTL
    五大常用算法之三:贪心算法
    python字符串处理
    判断视图存不存在
    判断插入的数据在表中存不存在
    sql因为发现对象名称 'dbo.Ct2' 和索引名称 'PK_Ct2' 有重复的键,所以ALTER TABLE ALTER COLUMN 。。。 失败。
    C# MD5算法 16 32 大小写
    制作VS2022中文离线安装包
  • 原文地址:https://www.cnblogs.com/lizijuna/p/11907404.html
Copyright © 2011-2022 走看看