Tomcat 9 错误 - mysql-cj-abandoned-connection-cleanup
Tomcat 9 error - mysql-cj-abandoned-connection-cleanup
我有一个程序 运行 在 Tomcat 9.
当我重启问题时,显示上面的警告:
05-Feb-2021 09:48:34.211 WARNING [Thread-5] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [AWSApps] appears to have started a thread named [mysql-cj-abandoned-connection-cleanup] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
org.apache.catalina.loader.WebappClassLoaderBase.trackLastModified(WebappClassLoaderBase.java:963)
org.apache.catalina.loader.WebappClassLoaderBase.findResource(WebappClassLoaderBase.java:941)
org.apache.catalina.loader.WebappClassLoaderBase.getResource(WebappClassLoaderBase.java:1057)
com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.checkThreadContextClassLoader(AbandonedConnectionCleanupThread.java:117)
com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:84)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
java.lang.Thread.run(Thread.java:748)
Tomcat 版本:Tomcat 9
虚拟机:java-8-openjdk-amd64
Mysql 驱动程序:mysql-连接器-java-8.0.20
server.xml
driverClassName="com.mysql.jdbc.Driver"
我试过把server.xml改成
com.mysql.cj.jdbc.Driver
但是Catalina.out中仍然有警告。
有解决问题的指南吗?
谢谢。
如果您的 Web 应用程序在 WEB-INF/lib
文件夹中有 MySQL JDBC 驱动程序的副本,则 Tomcat 中使用的特殊 delegation rules for classloaders 将 select Web 应用程序的驱动程序副本,而不是全局驱动程序副本。
这将在 bootstrap 类加载器中创建对应用程序类加载器的两个引用:
- 驱动程序将在
DriverManager
中注册(在 bootstrap 类加载器中),
- 驱动程序将创建一个新线程,
ContextClassLoader
设置为 webapp 类加载器。
两个引用都可能造成内存泄漏。
备注: 即使您不直接使用 DriverManager
也会发生这种情况,但是某些数据库池库(将在end) 或者如果您在 <Context>
中定义了 JNDI <Resource>
。只有在 <GlobalNamingResources>
中定义的 <Resource>
的情况不受影响。
解决问题你可以:
- 要么从您的
WEB-INF/lib
目录中删除数据库驱动程序,
- 当应用程序通过调用
DriverManager.deregister
停止时撤消这些更改,例如在 ServletContextListener 中:
public class JdbcDriverListener implements ServletContextListener {
/**
* Deregisters the JDBC drivers distributed with the application.
*/
@Override
public void contextDestroyed(ServletContextEvent event) {
final ClassLoader cl = event.getServletContext().getClassLoader();
final Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
final Driver driver = drivers.nextElement();
// We deregister only the classes loaded by this application's classloader
if (driver.getClass().getClassLoader() == cl) {
try {
DriverManager.deregisterDriver(driver);
} catch (SQLException e) {
event.getServletContext().log("JDBC Driver deregistration failure.", e);
}
}
}
}
/**
* Registers the JDBC drivers distributed with the application.
*/
@Override
public void contextInitialized(ServletContextEvent event) {
Iterator<@NonNull Driver> driversIterator = ServiceLoader.load(Driver.class).iterator();
while (driversIterator.hasNext()) {
try {
// Instantiates the driver
driversIterator.next();
} catch (Throwable t) {
event.getServletContext().log("JDBC Driver registration failure.", t);
}
}
}
}
编辑:我将评论中的信息合并到答案中。
我有一个程序 运行 在 Tomcat 9.
当我重启问题时,显示上面的警告:
05-Feb-2021 09:48:34.211 WARNING [Thread-5] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [AWSApps] appears to have started a thread named [mysql-cj-abandoned-connection-cleanup] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
org.apache.catalina.loader.WebappClassLoaderBase.trackLastModified(WebappClassLoaderBase.java:963)
org.apache.catalina.loader.WebappClassLoaderBase.findResource(WebappClassLoaderBase.java:941)
org.apache.catalina.loader.WebappClassLoaderBase.getResource(WebappClassLoaderBase.java:1057)
com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.checkThreadContextClassLoader(AbandonedConnectionCleanupThread.java:117)
com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:84)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
java.lang.Thread.run(Thread.java:748)
Tomcat 版本:Tomcat 9 虚拟机:java-8-openjdk-amd64 Mysql 驱动程序:mysql-连接器-java-8.0.20
server.xml
driverClassName="com.mysql.jdbc.Driver"
我试过把server.xml改成
com.mysql.cj.jdbc.Driver
但是Catalina.out中仍然有警告。
有解决问题的指南吗?
谢谢。
如果您的 Web 应用程序在 WEB-INF/lib
文件夹中有 MySQL JDBC 驱动程序的副本,则 Tomcat 中使用的特殊 delegation rules for classloaders 将 select Web 应用程序的驱动程序副本,而不是全局驱动程序副本。
这将在 bootstrap 类加载器中创建对应用程序类加载器的两个引用:
- 驱动程序将在
DriverManager
中注册(在 bootstrap 类加载器中), - 驱动程序将创建一个新线程,
ContextClassLoader
设置为 webapp 类加载器。
两个引用都可能造成内存泄漏。
备注: 即使您不直接使用 DriverManager
也会发生这种情况,但是某些数据库池库(将在end) 或者如果您在 <Context>
中定义了 JNDI <Resource>
。只有在 <GlobalNamingResources>
中定义的 <Resource>
的情况不受影响。
解决问题你可以:
- 要么从您的
WEB-INF/lib
目录中删除数据库驱动程序, - 当应用程序通过调用
DriverManager.deregister
停止时撤消这些更改,例如在 ServletContextListener 中:
public class JdbcDriverListener implements ServletContextListener {
/**
* Deregisters the JDBC drivers distributed with the application.
*/
@Override
public void contextDestroyed(ServletContextEvent event) {
final ClassLoader cl = event.getServletContext().getClassLoader();
final Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
final Driver driver = drivers.nextElement();
// We deregister only the classes loaded by this application's classloader
if (driver.getClass().getClassLoader() == cl) {
try {
DriverManager.deregisterDriver(driver);
} catch (SQLException e) {
event.getServletContext().log("JDBC Driver deregistration failure.", e);
}
}
}
}
/**
* Registers the JDBC drivers distributed with the application.
*/
@Override
public void contextInitialized(ServletContextEvent event) {
Iterator<@NonNull Driver> driversIterator = ServiceLoader.load(Driver.class).iterator();
while (driversIterator.hasNext()) {
try {
// Instantiates the driver
driversIterator.next();
} catch (Throwable t) {
event.getServletContext().log("JDBC Driver registration failure.", t);
}
}
}
}
编辑:我将评论中的信息合并到答案中。