Using Multiple Oracle JDBC drivers in one Java application?

If you don't register the drivers you avoid them being loaded by the same classloader.

Then you can create connections using the two different drivers by loading them through separate classloaders:

// Oracle 8 connection
File jar = new File("/path/to/oracle8.jar");
URL[] cp = new URL[1];
cp[0] = jar.toURI().toURL();
URLClassLoader ora8loader = new URLClassLoader(cp, ClassLoader.getSystemClassLoader());
Class drvClass = ora8loader.loadClass("oracle.jdbc.driver.OracleDriver");
Driver ora8driver = (Driver)drvClass.newInstance();

Properties props = new Properties();
// "user" instead of "username"
props.setProperty("user", "my-user");
props.setProperty("password", "my-password");
Connection ora8conn = ora8driver.connect("jdbc:oracle:thin:@some-oracle-8-server:port:sid",props);

Then do the same for the Oracle 12 driver.

You might also be able to still use the "other" driver through DriverManager, but I'm not sure about that.

There are some corner cases where accessing Oracle specific classes gets a bit complicated, but in general you can use the connections created through this without any problems.


I see two different solutions for different constellations.

(Using same (?) classes with different versions normally would be an idealh use case for OSGi, or if your application is a NetBeans RCP, their modular system. This works using class loaders that separate the software into modules, so one in different modules may load different jars with different versions of the same product.)

(Alternatively one might a different application with its own Oracle jar that is accessed using RMI.)

You might use the same technique: either write your own delegating ClassLoader that loads the right jar, or use the conceptually simpler RMI that however requires managing system resources.

So

  1. Do not use imports from the vendors; that is contrary to the vendor indepence of JDBC.

  2. Ensure that javax.sql interfaces come from a java-ee jar.


Picking the ClassLoader solution:

It would be best to make your own delegating Driver say with a protocol jdbc:myswitch:8: .... It could then use two different class loader instances. For instance using an URLClassLoader with a file:/... path.

One could make two separate instances of the custom delegating driver, so one can use the Delegate pattern.

public static class MySwitchDriver implements Driver {

    private final String oraURIPrefix;
    private final Driver delegateDriver;

    public MySwitchDriver(String oraURIPrefix) {
        this.oraURIPrefix = oraURIPrefix; // "8:" or "12:"
        String jarFileURI = oraURIPrefi.equals("8")
            ? "file:/... .jar" : "file:/... .jar";
        URLClassLoader classLoader = new URLClassLoader(...);
        delegateDriver = classLoader.loadClass(
                "oracle.jdbc.driver.OracleDriver", true);
        DriverManager.registerDriver(this);
    }

    private String delegateURL(String url) {
        // Something safer than this:
        return "jdbc:" + url.substring(
                "jdbc:myswitch".length
                + oraURIPrefix.length);
    }

    @Override
    public Connection connect(String url, Properties info)
            throws SQLException {
        String url2 = delegateURL(url);
        Properties info2 = info;
        return delegateDriver.connect(url2, info2);
    }

    @Override
    public boolean acceptsURL(String url) throws SQLException {
        return url.startsWith("jdbc:myswitch:" + oraURIPrefix)
            && delegateDriver.acceptsURL(delegateURL(url));
    }
...
}

Tags:

Java

Oracle

Jdbc