在一个 Java 应用程序中使用多个 Oracle JDBC 驱动程序?

Using Multiple Oracle JDBC drivers in one Java application?

我想通过 JDBC 连接到两个不同的 Oracle 数据库(一个 8.0.5.0.0 和一个 12c)。我确实有两个 JDBC 驱动程序,它们可以通过简单的 "hello world" 应用程序单独成功地连接到相应的数据库。下面,我将它们放在一个 Java 应用程序中,不幸的是它不再工作了(两个驱动程序都被加载)。

我读过这个post:Handle multiple JDBC drivers from the SAME VENDOR。提到的选项1可能有办法,但似乎有一个主要问题:

好像OracleDataSource在旧的8版本驱动中还没有,只是在以后的版本中引入了(12c版本驱动中有)。

关于如何使用一个 Java 应用程序和两个 JDBC 驱动程序连接到这两个 Oracle 数据库的任何提示?

import java.sql.*;

class db {
    public static void main (String args []) throws SQLException {

        // Oracle 8 connection
        DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
        Connection c1 = DriverManager.getConnection(
                "jdbc:oracle:thin:@some-oracle-8-server:port:sid",
                "my-user",
                "my-password");
        Statement s1 = c1.createStatement ();
        ResultSet r1 = s1.executeQuery ("SELECT banner FROM V$VERSION WHERE banner LIKE 'Oracle%'");
        while (r1.next ()) {
            System.out.println(r1.getString (1));
        }
        c1.close();

        // Oracle 12 connection
        Connection c2 = DriverManager.getConnection(
                "jdbc:oracle:thin:@some-oracle-12-server:port:sid",
                "my-user",
                "my-password");
        Statement s2 = c2.createStatement ();
        ResultSet r2 = s2.executeQuery ("SELECT banner FROM V$VERSION WHERE banner LIKE 'Oracle%'");
        while (r2.next ()) {
            System.out.println(r2.getString (1));
        }
        c2.close();
    }
}

感谢您的光临!

我看到针对不同星座的两种不同解决方案。

(使用不同版本的相同 (?) classes 通常是 OSGi 的理想用例,或者如果您的应用程序是 NetBeans RCP,它们的模块化系统。这使用 class 加载器将软件分成模块,因此不同模块中的一个可以加载具有同一产品不同版本的不同 jar。)

(或者一个不同的应用程序可能有自己的 Oracle jar,使用 RMI 访问。)

您可以使用相同的技术:编写您自己的委托 ClassLoader 来加载正确的 jar,或者使用概念上更简单的 RMI,但需要管理系统资源。

所以

  1. 不要使用供应商的进口产品;这与 JDBC.

    的供应商独立性相反
  2. 确保 javax.sql 接口来自 java-ee jar。


选择类加载器解决方案:

最好让您自己的委托驱动程序使用协议 jdbc:myswitch:8: ... 说。然后它可以使用两个不同的 class 加载器实例。例如,使用带有 file:/... 路径的 URLClassLoader。

可以创建自定义委托驱动程序的两个独立实例,这样就可以使用委托模式。

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));
    }
...
}

如果您不注册驱动程序,则可以避免它们被同一个类加载器加载。

然后您可以使用两个不同的驱动程序创建连接,方法是通过单独的类加载器加载它们:

// 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);

然后对 Oracle 12 驱动程序执行相同的操作。

可能 也可以通过 DriverManager 使用 "other" 驱动程序,但我不确定。

在某些极端情况下,访问特定于 Oracle 的 类 会变得有点复杂,但通常您可以毫无问题地使用由此创建的连接。

您可以使用工厂设计模式来获得您想要的连接,然后将其存储一些单例,这将与每个数据库建立连接。

因此,您的每个数据库连接都是单例,并且由工厂使用给定的 ENUM 实例化,您将他作为参数。