1

I'm working on a Java EE project (configuration below) and I face what seems to be a regular exception: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver.

I'm working with Eclipse, an embedded Tomcat 7 and Maven, and even if the driver is found for the tests, it is not found by Tomcat.

I searched for some answers 1, 2 and 3 but the advices were unclear: It is recommended to change the mysql-connector-java to provided, and manually copy the dependency in the server (not clear how).

Yet I do not understand why I should exclude the dependency for deployment (scope provided) and add it manually, isn't it contradictory?

After reading the Maven documentation, I feel like the running environment would need the dependency, and therefore the compile scope is best suited.

Well as you can see I'm trying to figure these things out, so I would rather have an explanation than a magic fix.

The configuration:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.26</version>
</dependency>

The database properties:

  • URL = jdbc:mysql://127.0.0.1:3306/XXX-db?zeroDateTimeBehavior=convertToNull
  • USERBD = XXX
  • PASSWORDBD = XXX
  • DRIVER = com.mysql.jdbc.Driver

The properties loading:

static {
    try {

        Properties databaseProperties = new Properties();
        InputStream inputStream = DatabaseConnection.class.getClassLoader()
                .getResourceAsStream(PROPERTIES_FILE);
        if (inputStream != null) {
            databaseProperties.load(inputStream);
        } else {
            throw new FileNotFoundException(
                    "property file '" + PROPERTIES_FILE + "' not found in the classpath");
        }
        Class.forName(databaseProperties.getProperty("DRIVER"));
        USERBD = databaseProperties.getProperty("USERBD");
        PASSWORDBD = databaseProperties.getProperty("PASSWORDBD");
        URL = databaseProperties.getProperty("URL");
    } catch (ClassNotFoundException | IOException e) {
        e.printStackTrace();
    }
}
Community
  • 1
  • 1
slonepi
  • 164
  • 2
  • 6
  • I'm not sure why someone would recommend not embedding JDBC drivers in a WAR, unless the application server already provides them (which is not the case by default with Tomcat IIRC). If it works with the default scope (`compile`), I would leave it as is. – Bastien Jansen Feb 20 '17 at 19:35
  • 1
    Tomcat provides a connection pool, which is a must-have for any seriousweb application. So if you don't also have, configure and use a connection pool in your war, you'd better mark the dependency as provided, add it to tomcat's libraries, and configure the tomcat connection pool as explained in the tomcat documentation. Another advantage is that the tuning of the connection pool settings doesn't need any rebuild of the war. But if you have a properly configured connection pool in your war, it's fine, too. – JB Nizet Feb 20 '17 at 19:57

1 Answers1

2

Tomcat 7 JNDI docs give you the answer: put them in the Tomcat /lib folder.

The JRE Memory Leak Prevention Listener that is included with Apache Tomcat solves this by triggering the drivers scan during Tomcat startup. This is enabled by default. It means that only libraries visible to the listener such as the ones in $CATALINA_BASE/lib will be scanned for database drivers. If you are considering disabling this feature, note that the scan would be triggered by the first web application that is using JDBC, leading to failures when this web application is reloaded and for other web applications that rely on this feature.

Thus, the web applications that have database drivers in their WEB-INF/lib directory cannot rely on the service provider mechanism and should register the drivers explicitly.

duffymo
  • 305,152
  • 44
  • 369
  • 561