报错:

严重: Web应用程序 [/XXX_war_exploded] 注册了JDBC驱动程序 [com.mysql.cj.jdbc.Driver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。
……
在这里插入图片描述

问题描述

在用intellij开发javaweb的时候,修改了前端代码只需update resources即可,一两秒即可完成。但是如果修改了后端的代码,必须要restart server或者redeploy,如图
在这里插入图片描述
restart server就是重启tomcat服务器,比较慢,如果只是改了一个小地方想试一下,就需要等待十秒钟,感觉非常不好。而redeploy就是不关闭服务器,而是把项目重新部署上去,也只需要一两秒。但是redeploy的时候会出现如上问题(有些人可能不会,这个我也搞不清楚)就是说驱动程序不会在项目被销毁时自动注销,那么如果再部署一次就又会有一个驱动。我看到一个比较详细的解释是这样的

自6.0.24版以来,Tomcat附带了内存泄漏检测特性,当Webapp的驱动程序中有一个兼容JDBC4.0的驱动程序时,这会导致这种警告消息。
/WEB-INF/lib的auto-register时使用ServiceLoaderAPI但这不是自动的-注销在webapp关机期间。
这个消息纯粹是非正式的,Tomcat已经相应地采取了防止内存泄漏的行动。你能做什么?无视那些警告。
托姆凯特做的很好。实际的bug在其他人的代码中(有问题的JDBC驱动程序),而不是在您的代码中。
很高兴Tomcat正确地完成了它的工作,并等待JDBC驱动程序供应商修复它,以便您可以升级驱动程序。
另一方面,您不应该将JDBC驱动程序放在webapp中/WEB-INF/lib,但仅限于服务器的/lib…如果你还把它放在webapp里/WEB-INF/lib,
然后您应该手动注册并使用ServletContextListener.降级到Tomcat 6.0.23或更高版本,这样您就不会被这些警告所困扰。
但它会悄无声息地漏掉记忆。不知道这到底是不是好消息。这种类型的内存泄漏是背后的主要原因之一。

outOfMemoryError问题在Tomcat热部署期间。将JDBC驱动程序移动到Tomcat/lib文件夹,并有一个连接池数据源来管理驱动程序。
请注意,Tomcat的内置DBCP在关闭时没有正确地取消注册驱动程序。
参见bugDBCP-322作为WONTFIX关闭。您希望将DBCP替换为另一个连接池,它比DBCP做得更好。例如HikariCP, BoneCP,或者也许TomcatJDBC池.

解决办法

直接无视肯定是不好的,降低tomcat的版本也不是一个好的解决方案,将JDBC驱动程序放在服务器的/lib下也行不通,因为我需要在intellij中进行开发,如果在webapp中没有相关jar包,虽然最后运行的效果一样,但是intellij对我来说就和记事本没有区别,甚至还会因为检测不到所需类而报红。
所以只能加一个监听类手动注销这些东西。

首先新建监听类,然后在web.xml中加一个刚刚新建的类的监听器,在contextDestroyed中手动取消这些线程,如图:
在这里插入图片描述
在这里插入图片描述

代码

contextDestroyed方法

//手动取消c3p0数据库连接池
        try {
            DataSources.destroy(JdbcUtils.getDataSource());//getDataSource方法获取c3p0数据源
            System.out.println("关闭数据库连接池成功!");
        } catch (SQLException e) {
            e.printStackTrace();
        }

        //手动取消驱动程序的注册:
        Enumeration drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = (Driver) drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
                System.out.println("deregistering jdbc driver: "+driver);
            } catch (SQLException e) {
                e.printStackTrace();
                System.out.println("Error deregistering driver"+driver);
            }
        }
        //手动停止名为[mysql-cj-abandoned-connection-cleanup]的线程
        AbandonedConnectionCleanupThread.uncheckedShutdown();

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <listener>
        <listener-class>contextListener.ContextListener</listener-class>
    </listener>
</web-app>
Logo

更多推荐