java - Tomcat 9 错误 - 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 JVM:java-8-openjdk-amd64 Mysql 驱动程序:mysql-connector-java-8.0.20
服务器.xml
driverClassName="com.mysql.jdbc.Driver"
我试图将 server.xml 更改为
com.mysql.cj.jdbc.Driver
但在 Catalina.out 中仍有警告。
有解决问题的指南吗?
谢谢你。
解决方案
如果您的 Web 应用程序在文件夹中有 MySQL JDBC 驱动程序的副本,则 Tomcat 中使用的类加载器WEB-INF/lib
的特殊委托规则将选择 Web 应用程序的驱动程序副本而不是全局驱动程序副本。
这将在引导类加载器中的应用程序类加载器上创建两个引用:
- 驱动程序将被注册
DriverManager
(在引导类加载器中), - 驱动程序将创建一个
ContextClassLoader
设置为 webapp 类加载器的新线程。
这两个引用都可能造成内存泄漏。
备注:即使您不DriverManager
直接使用,但某些数据库池库(最终将使用DriverManager
)或者如果您<Resource>
在<Context>
. 只有在 中<Resource>
定义的情况<GlobalNamingResources>
不受影响。
要解决问题,您可以:
- 从您的
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);
}
}
}
}
编辑:我将评论中的信息合并到答案中。
推荐阅读
- css - CSS Right to Left @keyframes transform:-100% to transform none
- python - Scrapy:TypeError:__init__()缺少1个必需的位置参数:'url'
- javascript - Downloading a file from spring rest api
- sas - SAS 从另一个程序中的宏调用一个程序
- google-cloud-storage - GCS:重试 BlobWriteChannel.flushBuffer 中的 410 个错误
- asp.net-core - 处理未授权的 OpenID 连接策略?
- python - 使用 FilePond(React 组件)将图像上传到 Flask 服务器
- vue.js - 提高 Vue.js 应用程序的性能
- permissions - 无法通过 Azure Dev Ops 代理共享文件夹
- r - 从 R 中的图像 URL 异步下载图像