Tomcat 9 错误 - mysql-cj-abandoned-connection-cleanup [英] Tomcat 9 error - mysql-cj-abandoned-connection-cleanup
问题描述
我有一个在 Tomcat 9 中运行的程序.
I have a program that running in Tomcat 9.
当我重新启动问题时,它显示了上面的警告:
When I restarted the problem, it shows the above warning:
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 9JVM:java-8-openjdk-amd64mysql驱动:mysql-connector-java-8.0.20
Tomcat Version : Tomcat 9 JVM : java-8-openjdk-amd64 Mysql Driver : mysql-connector-java-8.0.20
server.xml
driverClassName="com.mysql.jdbc.Driver"
我已尝试将 server.xml 更改为
I have tried to change the server.xml into
com.mysql.cj.jdbc.Driver
但是在 Catalina.out 中仍然有警告.
But there is still warning in Catalina.out.
是否有解决问题的指南?
Is there any guide to solve the issue?
谢谢.
推荐答案
如果您的 Web 应用程序在 WEB-INF/lib
文件夹中有 MySQL JDBC 驱动程序的副本,则特殊的 类加载器的委托规则 将选择 Web 应用程序的副本驱动程序而不是全局驱动程序.
If your web application has a copy of the MySQL JDBC driver in the WEB-INF/lib
folder, the special delegation rules for classloaders used in Tomcat will select the web application's copy of the driver instead of the global one.
这将在引导类加载器中对应用程序的类加载器创建两个引用:
That will create two references on your application's classloader in the bootstrap classloader:
- 驱动程序将注册到
DriverManager
(在引导类加载器中), - 驱动程序将创建一个新线程,并将
ContextClassLoader
设置为 webapp 类加载器.
- The driver will be registered with
DriverManager
(in the bootstrap classloader), - The driver will create a new thread with the
ContextClassLoader
set to the webapp classloader.
两个引用都会造成内存泄漏.
Both references can create a memory leak.
备注:即使您不直接使用 DriverManager
,而是使用某些数据库池库(将在其中使用 DriverManager
最后)或者如果您在
中定义了 JNDI
.只有在
中定义的
不受影响.
Remark: This happens even if you don't use a DriverManager
directly, but some database pooling library (which will use DriverManager
in the end) or if you define a JNDI <Resource>
in your <Context>
. Only the case of a <Resource>
defined in the <GlobalNamingResources>
is not affected.
要解决问题,您可以:
- 从您的
WEB-INF/lib
目录中删除数据库驱动程序, - 在应用程序停止时通过调用
DriverManager.deregister
来撤销这些更改,例如在 ServletContextListener 中:
- either remove the database driver from your
WEB-INF/lib
directory, - reverse these changes when the application stops by calling
DriverManager.deregister
, e.g. in a 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);
}
}
}
}
我将评论中的信息合并到答案中.
I merge the information from the comments into the answer.
这篇关于Tomcat 9 错误 - mysql-cj-abandoned-connection-cleanup的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!