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

时间:2015-01-27 09:57:52

标签: java oracle jdbc

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

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

旧版本8驱动程序中似乎尚不存在OracleDataSource,并且仅在更高版本中引入(在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();
    }
}

感谢adavnce!

3 个答案:

答案 0 :(得分:7)

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

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

// 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使用“其他”驱动程序,但我不确定。

在某些极端情况下,访问Oracle特定类会变得有点复杂,但一般情况下,您可以使用通过此创建的连接而不会出现任何问题。

答案 1 :(得分:1)

我为不同的星座看到了两种不同的解决方案。

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

(或者,可以使用RMI访问其自己的Oracle jar的不同应用程序。)

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

所以

  1. 不要使用供应商的进口商品;这与供应商独立的JDBC相反。

  2. 确保javax.sql接口来自java-ee jar。


  3. 选择ClassLoader解决方案:

    最好让自己的委托驱动程序说出协议jdbc:myswitch:8: ...。然后它可以使用两个不同的类加载器实例。例如,使用带有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));
        }
    

答案 2 :(得分:0)

你可以使用工厂设计模式来获得你想要的连接,然后存储一些Singleton,它可以连接到每个数据库。

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