严重: Web应用程序 [/XXX_war_exploded] 注册了JDBC驱动程序 [com.mysql.cj.jdbc.Driver],但在Web应用程序停止时无法注销它。
报错:
严重: 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>