Драйвер JDBC был принудительно незарегистрирован Tomcat 7, почему?

У меня есть проблема в tomcat 7, и вот некоторые сведения об этом,

1 - У меня есть это сообщение:

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 - Когда я перезагружаю приложение, проблема решена в течение примерно 20 часов, а затем возвращается снова.

3 - У меня около 10 приложений, развернутых на tomcat, но только 2 из них получают эту ошибку.

4 - проблема не существовала от попрошайничества с этими 2 приложениями, но появилась примерно через 2 недели.

Итак, как я могу решить эту проблему и связан ли это с моим кодом?

Ответы

Ответ 1

Когда вы останавливаете веб-приложение в Tomcat, оно пытается завершить запущенные потоки и закрывает кучу ресурсов, например драйверы JDBC. Хотя в этом случае он способен их закрыть, безопаснее делать это самостоятельно.

Вы можете сделать это в ServletContextListener. Я выполнил мою работу следующим образом

@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 запускает Thread, который Tomcat не может закрыть. Для текущих версий (5.1.23+) они предоставили класс AbandonedConnectionCleanupThread для закрытия порожденного Thread, как вы можете видеть выше.

Ответ 2

Если у вас есть драйвер Connector/J JDBC в каждом каталоге webapp WEB-INF/lib, тогда у вас, скорее всего, будут проблемы со всеми вашими веб-приложениями, а не только с этим.

Если вы используете пул соединений Tomcat JDBC, вам следует поместить драйвер Connector/J в каталог Tomcat lib/ и удалить его со всех ваших веб-приложений. Если вы поддерживаете свой собственный пул подключений из своего собственного приложения, вам необходимо будет настроить, чтобы драйвер JDBC был деинфицирован с глобальным DriverManager. Еще лучше, используйте драйвер, не регистрирующий Connector/J вместо драйвера регистрации, и вам не придется беспокоиться об этих утечках, которые Tomcat фактически защищает вас.