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

严重: Web应用程序 [/XXX_war_exploded] 注册了JDBC驱动程序 [com.mysql.cj.jdbc.Driver],但在Web应用程序停止时无法注销它。

程序员文章站 2024-03-14 17:01:28
...

报错:

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

问题描述

在用intellij开发javaweb的时候,修改了前端代码只需update resources即可,一两秒即可完成。但是如果修改了后端的代码,必须要restart server或者redeploy,如图
严重: Web应用程序 [/XXX_war_exploded] 注册了JDBC驱动程序 [com.mysql.cj.jdbc.Driver],但在Web应用程序停止时无法注销它。
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中手动取消这些线程,如图:
严重: Web应用程序 [/XXX_war_exploded] 注册了JDBC驱动程序 [com.mysql.cj.jdbc.Driver],但在Web应用程序停止时无法注销它。
严重: Web应用程序 [/XXX_war_exploded] 注册了JDBC驱动程序 [com.mysql.cj.jdbc.Driver],但在Web应用程序停止时无法注销它。

代码

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>