简体   繁体   中英

Tomcat 9 error - mysql-cj-abandoned-connection-cleanup

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 Version: Tomcat 9 JVM: java-8-openjdk-amd64 Mysql Driver: mysql-connector-java-8.0.20

server.xml

 driverClassName="com.mysql.jdbc.Driver"

I have tried to change the server.xml into

com.mysql.cj.jdbc.Driver

But there is still warning in Catalina.out.

Is there any guide to solve the issue?

Thank you.

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:

  • 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.

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.

To solve the problem you can:

  • either remove the database driver from your WEB-INF/lib directory,
  • reverse these changes when the application stops by calling DriverManager.deregister , eg in a ServletContextListener:
public class DeregisterDriverListener implements ServletContextListener {
   
   @Override
   public void contextDestroyed(ServletContextEvent event) {
      // Your webapp classloader
      final ClassLoader cl = Thread.currentThread().getContextClassLoader();
      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 problem.", e);
            }
         }
      }
   }

   @Override
   public void contextInitialized(ServletContextEvent event) {
      // NOP
   }
}

Edit: I merge the information from the comments into the answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM