To prevent a memory leak, the JDBC Driver has been forcibly unregistered

后端 未结 14 1472
执念已碎
执念已碎 2020-11-22 02:15

I am getting this message when I run my web application. It runs fine but I get this message during shutdown.

SEVERE: A web application registered the

相关标签:
14条回答
  • 2020-11-22 02:57

    Solution for per-app deployments

    This is a listener I wrote to solve the problem: it autodetects if the driver has registered itself and acts accordingly.it

    Important: it is meant to be used ONLY when the driver jar is deployed in WEB-INF/lib, not in the Tomcat /lib, as many suggest, so that each application can take care of its own driver and run on a untouched Tomcat. That is the way it should be IMHO.

    Just configure the listener in your web.xml before any other and enjoy.

    add near the top of web.xml:

    <listener>
        <listener-class>utils.db.OjdbcDriverRegistrationListener</listener-class>    
    </listener>
    

    save as utils/db/OjdbcDriverRegistrationListener.java:

    package utils.db;
    
    import java.sql.Driver;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.util.Enumeration;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    
    import oracle.jdbc.OracleDriver;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * Registers and unregisters the Oracle JDBC driver.
     * 
     * Use only when the ojdbc jar is deployed inside the webapp (not as an
     * appserver lib)
     */
    public class OjdbcDriverRegistrationListener implements ServletContextListener {
    
        private static final Logger LOG = LoggerFactory
                .getLogger(OjdbcDriverRegistrationListener.class);
    
        private Driver driver = null;
    
        /**
         * Registers the Oracle JDBC driver
         */
        @Override
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            this.driver = new OracleDriver(); // load and instantiate the class
            boolean skipRegistration = false;
            Enumeration<Driver> drivers = DriverManager.getDrivers();
            while (drivers.hasMoreElements()) {
                Driver driver = drivers.nextElement();
                if (driver instanceof OracleDriver) {
                    OracleDriver alreadyRegistered = (OracleDriver) driver;
                    if (alreadyRegistered.getClass() == this.driver.getClass()) {
                        // same class in the VM already registered itself
                        skipRegistration = true;
                        this.driver = alreadyRegistered;
                        break;
                    }
                }
            }
    
            try {
                if (!skipRegistration) {
                    DriverManager.registerDriver(driver);
                } else {
                    LOG.debug("driver was registered automatically");
                }
                LOG.info(String.format("registered jdbc driver: %s v%d.%d", driver,
                        driver.getMajorVersion(), driver.getMinorVersion()));
            } catch (SQLException e) {
                LOG.error(
                        "Error registering oracle driver: " + 
                                "database connectivity might be unavailable!",
                        e);
                throw new RuntimeException(e);
            }
        }
    
        /**
         * Deregisters JDBC driver
         * 
         * Prevents Tomcat 7 from complaining about memory leaks.
         */
        @Override
        public void contextDestroyed(ServletContextEvent servletContextEvent) {
            if (this.driver != null) {
                try {
                    DriverManager.deregisterDriver(driver);
                    LOG.info(String.format("deregistering jdbc driver: %s", driver));
                } catch (SQLException e) {
                    LOG.warn(
                            String.format("Error deregistering driver %s", driver),
                            e);
                }
                this.driver = null;
            } else {
                LOG.warn("No driver to deregister");
            }
    
        }
    
    }
    
    0 讨论(0)
  • 2020-11-22 03:00

    I will add to this something I found on the Spring forums. If you move your JDBC driver jar to the tomcat lib folder, instead of deploying it with your webapp, the warning seems to disappear. I can confirm that this worked for me

    http://forum.springsource.org/showthread.php?87335-Failure-to-unregister-the-MySQL-JDBC-Driver&p=334883#post334883

    0 讨论(0)
  • 2020-11-22 03:00

    I was having a similar problem, but additionally I was getting a Java Heap Space error anytime I modified/saved JSP pages with Tomcat server running, therefore the context were not fully recharged.

    My versions were Apache Tomcat 6.0.29 and JDK 6u12.

    Upgrading JDK to 6u21 as suggested in References section of URL http://wiki.apache.org/tomcat/MemoryLeakProtection solved the Java Heap Space problem (context now reloads OK) although JDBC Driver error still appears.

    0 讨论(0)
  • 2020-11-22 03:05

    This is purely driver registration/deregistration issue in mysql`s driver or tomcats webapp-classloader. Copy mysql driver into tomcats lib folder (so its loaded by jvm directly, not by tomcat), and message will be gone. That makes mysql jdbc driver to be unloaded only at JVM shutdown, and noone cares about memory leaks then.

    0 讨论(0)
  • 2020-11-22 03:06

    Since version 6.0.24, Tomcat ships with a memory leak detection feature, which in turn can lead to this kind of warning messages when there's a JDBC 4.0 compatible driver in the webapp's /WEB-INF/lib which auto-registers itself during webapp's startup using the ServiceLoader API, but which did not auto-deregister itself during webapp's shutdown. This message is purely informal, Tomcat has already taken the memory leak prevention action accordingly.

    What can you do?

    1. Ignore those warnings. Tomcat is doing its job right. The actual bug is in someone else's code (the JDBC driver in question), not in yours. Be happy that Tomcat did its job properly and wait until the JDBC driver vendor get it fixed so that you can upgrade the driver. On the other hand, you aren't supposed to drop a JDBC driver in webapp's /WEB-INF/lib, but only in server's /lib. If you still keep it in webapp's /WEB-INF/lib, then you should manually register and deregister it using a ServletContextListener.

    2. Downgrade to Tomcat 6.0.23 or older so that you will not be bothered with those warnings. But it will silently keep leaking memory. Not sure if that's good to know after all. Those kind of memory leaks are one of the major causes behind OutOfMemoryError issues during Tomcat hotdeployments.

    3. Move the JDBC driver to Tomcat's /lib folder and have a connection pooled datasource to manage the driver. Note that Tomcat's builtin DBCP does not deregister drivers properly on close. See also bug DBCP-322 which is closed as WONTFIX. You would rather like to replace DBCP by another connection pool which is doing its job better then DBCP. For example HikariCP, BoneCP, or perhaps Tomcat JDBC Pool.

    0 讨论(0)
  • 2020-11-22 03:08

    If you are getting this message from a Maven built war change the scope of the JDBC driver to provided, and put a copy of it in the lib directory. Like this:

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.18</version>
      <!-- put a copy in /usr/share/tomcat7/lib -->
      <scope>provided</scope>
    </dependency>
    
    0 讨论(0)
提交回复
热议问题