Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to register oracle jdbc driver on Tomcat 7.0.47 startup?

I copied ojdbc6.jar to the lib folder in the tomcat installation folder. When I deploy my Web App which makes use of the Oracle Driver in a JDBC Connection, the server says that the driver class can't be found, and I am forced to do DriverManager.registerDriver manually, then it works.

Can it be done so the driver is registered at startup and I don't have to do it manually neither create a connection pool?

like image 609
tonlika Avatar asked Nov 26 '13 17:11

tonlika


2 Answers

Can you clarify what you mean by "lib folder in the tomcat installation folder"? It should mean the /lib directly under your Tomcat root.

The Tomcat 7 docs say this:

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.

The right thing to do is to set up a JNDI data source rather than creating one in your code using DriverManager.

I'd also recommend matching the driver version to both your Oracle and JVM versions. JDK 6 has reached the end of its support life. JDK 7 is current production. I'd recommend upgrading from ojdbc6.jar if you're using JDK 7.

like image 91
duffymo Avatar answered Sep 21 '22 18:09

duffymo


I had the same issue when trying to use ojdbc7.jar with tomcat 8.0.20 on oracle's jdk 8_31.

I have put the ojdbc7.jar in $CATALINA_BASE/lib as suggested here : http://tomcat.apache.org/tomcat-8.0-doc/jndi-datasource-examples-howto.html and then expected java's service provider mechanism to register the driver using tomcat's "common" classloader, but it doesn't work and the driver does not get registered.

After a bit of debugging, It seems that tomcat's JreMemoryLeakPreventionListener initializes the DriverManager from the "system" classloader and not the "common" classloader (from tomcat's code) :

// Use the system classloader as the victim for all this
// ClassLoader pinning we're about to do.
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());

/*
* First call to this loads all drivers in the current class
* loader
*/
if (driverManagerProtection) {
  DriverManager.getDrivers();
}

The problem here is that the system classloader (in my case oracle's Launcher$AppClassLoader) has the following classpath :

file:$CATALINA_BASE/bin/bootstrap.jar
file:$CATALINA_BASE/bin/tomcat-juli.jar

Since ojbc7.jar is not in this classpath, no service provider will be discovered by the DriverManager, so your driver can only be explicitly registered since the scan is only done from a static block when the DriverManager class is loaded (which is it's fundamental flaw).

My first idea to fix this was to add the ojdbc jar to the system's classloader classpath in tomcat's $CATALINA_BASE/bin/setenv.sh like so :

CLASSPATH=$CATALINA_BASE/lib/ojdbc7.jar

With this, the driver is registered using the service provider mechanism from the JreMemoryLeakPreventionListener invocation using the system classloader.

You have to be very careful not to bring the ojdbc driver in your webapp's classloader (by having ojdbc in your WEB-INF/lib folder for instance) as those classes have priority over the ones from parent classloaders. It's a bit complex but the DriverManager itself may cause and additional registration of the driver from the webapp's classloaders when it calls Class.forName using the caller's classloader because it knows the class name from the registration during startup.

like image 41
mryan Avatar answered Sep 24 '22 18:09

mryan