Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JDBC Driver has been forcibly unregistered by Tomcat 7, why?

Tags:

java

tomcat

jdbc

I have a problem in tomcat 7, and here are some info about it,

1 - I have this message:

INFO: Reloading Context with name [/WebApp] has started
Oct 04, 2013 12:20:50 PM org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc
SEVERE: The web application [/WebApp] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

Oct 04, 2013 12:20:50 PM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: The web application [/WebApp] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak.
Oct 04, 2013 12:20:51 PM org.apache.catalina.core.StandardContext reload
INFO: Reloading Context with name [/WebApp] is completed

2 - When I reload the application the problem solved for about 20 hours then comes back again.

3 - I have about 10 application deployed on the tomcat but just 2 of them gets this error.

4 - the problem was not exist from the begging with these 2 apps but appeared from about 2 weeks.

So how can I solve this and is it related to my code?

like image 802
AAH Avatar asked Oct 04 '13 19:10

AAH


2 Answers

When you stop a web application in Tomcat, it tries to shutdown the threads it started and closes a bunch of resources, for example the JDBC drivers. Although in this case it is capable of closing them, it's safer to do it yourself.

You can do this in a ServletContextListener. I've implemented mine as follows

@WebListener // register it as you wish
public class ContainerContextClosedHandler implements ServletContextListener {
    private static final Logger logger = LoggerFactory.getLogger(ContainerContextClosedHandler.class);

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        // nothing to do
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        Enumeration<Driver> drivers = DriverManager.getDrivers();     

        Driver driver = null;

        // clear drivers
        while(drivers.hasMoreElements()) {
            try {
                driver = drivers.nextElement();
                DriverManager.deregisterDriver(driver);

            } catch (SQLException ex) {
                // deregistration failed, might want to do something, log at the very least
            }
        }

        // MySQL driver leaves around a thread. This static method cleans it up.
        try {
            AbandonedConnectionCleanupThread.shutdown();
        } catch (InterruptedException e) {
            // again failure, not much you can do
        }
    }

}

MySQL does starts a Thread that Tomcat cannot close. For current versions (5.1.23+), they've provided the AbandonedConnectionCleanupThread class to close the spawned Thread, as you can see above.

like image 140
Sotirios Delimanolis Avatar answered Oct 11 '22 18:10

Sotirios Delimanolis


If you have your Connector/J JDBC driver in each webapp's WEB-INF/lib directory, then you will likely have similar problems with all of your webapps -- not just this one.

If you are using Tomcat's JDBC connection pool, then you should put the Connector/J driver into Tomcat's lib/ directory and remove it from all of your webapps. If you are maintaining your own connection pool from within your own application, then you will have to arrange for the JDBC driver to be de-register itself with the global DriverManager. Better yet, use Connector/J's non-registering driver instead of the registering driver and then you don't have to worry about these kinds of leaks that Tomcat is actually protecting you from.

like image 41
Christopher Schultz Avatar answered Oct 11 '22 20:10

Christopher Schultz