2015-01-27 14 views
5

Desidero connettermi a due diversi database Oracle (uno 8.0.5.0.0 e uno 12c) tramite JDBC. Ho entrambi i driver JDBC che possono connettersi individualmente e correttamente al DB corrispondente tramite semplici applicazioni "ciao mondo". Sotto, ho riunito entrambi in un'unica applicazione Java, che sfortunatamente non funziona più (con entrambi i driver caricati).Utilizzo di più driver JDBC Oracle in un'applicazione Java?

Ho letto questo post: Handle multiple JDBC drivers from the SAME VENDOR. L'opzione 1 menzionata potrebbe essere la strada da percorrere, ma sembra esserci uno dei problemi principali:

Sembra che OracleDataSource non esiste ancora nel vecchio driver versione 8 e solo è stato introdotto nelle versioni successive (nel Esiste un driver di versione 12c).

Eventuali suggerimenti su come connettersi a questi due database Oracle con una singola applicazione Java e due driver 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(); 
    } 
} 

Grazie in anticipo!

+0

mm Vorrei utilizzare il driver più recente per entrambe le connessioni e definire solo 2 origini dati separate. La compatibilità con i driver jdbc di AFAIK è abbastanza solida. – BigMike

+0

Sono stupido, ma i driver oracle sono compatibili con le versioni precedenti. Il driver più recente non funziona per il database legacy? – Gimby

+2

Un driver 12c non funziona con un database 8i, no; sono compatibili con le versioni precedenti ma solo fino a un certo punto. Vedere [Domande frequenti JDBC] (http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#01_03) e [Oracle support note 207303.1] (http://support.oracle .com/epmos/faces/DocumentDisplay? id = 207303.1) –

risposta

6

Se non si registrano i driver si evita che vengano caricati dallo stesso classloader.

Quindi è possibile creare connessioni con i due piloti diversi caricandoli attraverso classloader separati:

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

poi fare lo stesso per il driver Oracle 12.

È possibile che sia ancora in grado di utilizzare il driver "altro" tramite DriverManager, ma non ne sono sicuro.

Ci sono alcuni casi in cui l'accesso a specifiche classi Oracle diventa un po 'complicato, ma in generale è possibile utilizzare le connessioni create attraverso questo senza problemi.

+0

È possibile che lì potrebbe essere un errore di battitura? La mia Eclipse si lamenta della riga "Driver ora8driver ..." che dice "Tipo mancata corrispondenza: impossibile convertire da Classe A Driver" – tschlein

+0

@kwirschau: hai ragione. 'loadClass()' restituisce un 'Class' non un' Driver'. Scusa stavo scrivendo dalla memoria. –

+0

Sì! Questo ha fatto il lavoro! Favolosa! – tschlein

1

Vedo due soluzioni diverse per diverse costellazioni.

(Uso stessi (?) Classi con diverse versioni normalmente sarebbe un caso d'uso idealh per OSGi, o se l'applicazione è un NetBeans RCP, il sistema modulare. Questo funziona utilizzando caricatori di classi che separano il software in moduli, così uno in diversi moduli possono caricare diversi vasi con differenti versioni dello stesso prodotto.)

(in alternativa si potrebbe una diversa applicazione con un proprio vaso Oracle a cui si accede utilizzando RMI.)

potrebbe usa la stessa tecnica: o scrivi il tuo delegante ClassLoader che carica il barattolo giusto o usa il più semplice dal punto di vista concettuale RMI che tuttavia richiede la gestione delle risorse di sistema.

Così

  1. Non utilizzare le importazioni dai fornitori; questo è contrario all'indipendenza del vendor di JDBC.

  2. Verificare che le interfacce javax.sql provengano da un jar java-ee.


Raccogliendo la soluzione ClassLoader:

Sarebbe meglio per rendere il proprio driver delegante dicono con un protocollo jdbc:myswitch:8: .... Potrebbe quindi utilizzare due diverse istanze del caricatore di classe. Ad esempio usando un URLClassLoader con un percorso file:/....

Si potrebbero creare due istanze separate del driver di delega personalizzato, quindi è possibile utilizzare il modello Delegare.

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

È possibile utilizzare il modello di progettazione di fabbrica per ottenere la connessione che si desidera avere, quindi memorizzarlo come Singleton che sta effettuando la connessione a ciascun database.

Quindi, ognuna delle connessioni del database è Singletons e, essendo instansato dalla Factory con ENUM specificato, lo si inserisce come parametro.

Problemi correlati