¿Usando múltiples controladores JDBC de Oracle en una aplicación Java?

Quiero conectarme a dos bases de datos Oracle diferentes (una 8.0.5.0.0 y una 12c) a través de JDBC. Tengo dos controladores JDBC que se pueden conectar individual y exitosamente al DB correspondiente a través de aplicaciones simples de “hello world”. A continuación, los he reunido en una sola aplicación Java, que desafortunadamente ya no funciona (con ambos controladores cargados).

He leído este post: Manejar múltiples controladores JDBC desde el MISMO VENDOR . La opción 1 mencionada podría ser el camino a seguir, pero parece haber un problema importante:

Parece que OracleDataSource aún no existe en el controlador de la versión 8 anterior y solo se ha introducido en versiones posteriores (en el controlador de la versión 12c existe).

¿Algún consejo sobre cómo conectarse a estas dos bases de datos Oracle con una sola aplicación Java y dos controladores JDBC?

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

Gracias en adavnce!

Si no registra los controladores, evite que se carguen con el mismo cargador de clases.

Luego, puede crear conexiones utilizando los dos controladores diferentes cargándolos a través de cargadores de clases separados:

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

Luego haga lo mismo con el controlador Oracle 12.

También podría seguir utilizando el “otro” controlador a través de DriverManager , pero no estoy seguro de eso.

Hay algunos casos de esquina donde acceder a clases específicas de Oracle se complica un poco, pero en general puede usar las conexiones creadas a través de esto sin ningún problema.

Veo dos soluciones diferentes para diferentes constelaciones.

(Usar las mismas clases (?) Con diferentes versiones normalmente sería un caso de uso ideal para OSGi , o si su aplicación es un NetBeans RCP, su sistema modular. Esto funciona utilizando cargadores de clases que separan el software en módulos, por lo que uno en diferentes módulos puede cargar diferentes jarras con diferentes versiones del mismo producto.)

(Alternativamente, se podría usar una aplicación diferente con su propio jar de Oracle al que se accede mediante RMI ).

Puede usar la misma técnica: ya sea que escriba su propio ClassLoader delegación que cargue el jar correcto, o use el RMI conceptualmente más simple que, sin embargo, requiere la administración de recursos del sistema.

Asi que

  1. No use importaciones de los vendedores; eso es contrario a la independencia del proveedor de JDBC.

  2. Asegúrese de que las interfaces javax.sql provienen de un java-ee jar.


Escogiendo la solución ClassLoader:

Sería mejor que tu propio conductor delegante dijera con un protocolo jdbc:myswitch:8: ... Entonces podría usar dos instancias de cargador de clases diferentes. Por ejemplo, utilizando un URLClassLoader con un file:/... ruta.

Uno podría crear dos instancias separadas del controlador de delegación personalizado, por lo que se puede usar el patrón Delegado.

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

Puede usar el patrón de diseño de Fábrica para obtener qué conexión le gustaría tener, luego, guárdelo con un Singleton que está haciendo su conexión a cada base de datos.

Entonces, cada una de las conexiones de su base de datos son Singletons, y al ser instaladas por la fábrica con el ENUM dado, lo pone como parámetro.