ODBC-Treiber

RealHAZZARD

Erfahrenes Mitglied
ODBC/JDBC-Treiber

Servus.

Edit: Ich meine natürlich die JDBC-Treiber

Ich möchte ein kleines Programm schreiben, welches auf
unterschiedliche SQL-Server (von unterschiedlichen Herstellern)
connecten kann(und natürlich auch darauf arbeiten).

Die Treiber kann man sich ja beim Hersteller herunterladen...
Meine Idee ist jetzt, dass der Benutzer mein Programm zur Laufzeit
mit neuen Treibern füttern kann. Und mein Programm soll dann erkennen,
welchen Treiber es da bekommen hat, von welchem Hersteller, und für
welche Versionen(SQL-Server) das kompatibel ist.
Natürlich soll mein Programm dann auch den Server fragen, auf welcher Version, und
von welchem Hersteller dieser rennt.

Hat da einer einen Lösungsansatz?
 
Zuletzt bearbeitet:
Java:
DriverManager.getDriver("jdbc:mysql://localhost/")
...eignet sich schonmal nicht für dynamisches "Herausfinden des Treibers".
Denn wie in dem Beispiel gezeigt, muss ich ja schonmal wissen,
von welchem Hersteller der DB-Server ist, um das subprotokoll angeben zu können.
Denn ohne geht es nicht. Und überhaupt. Was mach ich denn mit dem getDriver.
OK, es liefert einen Driver zurück, aber den muss ich doch nicht haben, wenn der
DriverManager den schon hat, oder versteh ich hier was falsch?
Gibt es vielleicht eine Möglichkeit, herauszufinden, von welchem Hersteller die Server kommt?
 
Zuletzt bearbeitet:
Hallo?

Naja...Ich hab da mal noch etwas gefunden, aber ich komm nicht wirklich damit klar.
Es geht um den Connector von Sun.
Der ist zum einen für die Treiber-Entwickler gedacht, zum anderen für Entwickler die einfach weitere JDBC - Treiber hinzufügen wollen (also doch eigentlich auch für mich).
Aber ich versteh nicht ganz was ich da wie verwenden soll.

Hat schonmal jemannd mit dem Connector von Sun gearbeitet?
 
Hallo!

... das ist ganz einfach... verwende einfach nicht mehr die ur-alte DriverManager Vorgehensweise, sondern verwende die javax.sql.DataSource implementierungen desentsprechenden JDBC Drivers... den JDBC Treiber (bzw. das entsprechende Jar) kannst du dynamisch zur Laufzeit laden.

Siehe auch hier:
Code:
/**
 * 
 */
package de.tutorials;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

/**
 * @author daritho
 * 
 */
public class DynamicClassPathExtensionExample {

    private static final String ORACLE_JDBC_POOL_ORACLE_DATA_SOURCE = "oracle.jdbc.pool.OracleDataSource";

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        addUrlToClasspath((URLClassLoader) Thread.currentThread()
                .getContextClassLoader(), new File(
                "D:/oracle/jdbc/lib/ojdbc14.jar").toURL());

        DataSource dataSource = createDataSourceForOracle(
                "user",
                "password",
                "localhost",
                1521,
                "ORCL",
                "thin");

        Connection con = dataSource.getConnection();
        con.close();
    }

    private static void addUrlToClasspath(URLClassLoader classLoader, URL url)
            throws NoSuchMethodException, IllegalAccessException,
            InvocationTargetException, MalformedURLException {
        Method method = URLClassLoader.class.getDeclaredMethod(
                "addURL",
                new Class[] { URL.class });
        method.setAccessible(true);
        method.invoke(classLoader, new Object[] { url });
    }

    private static DataSource createDataSourceForOracle(
            String user,
            String password,
            String serverName,
            int portNumber,
            String databaseName,
            String driverType) throws Exception {
        DataSource oracleDataSource = (DataSource) Thread.currentThread()
                .getContextClassLoader().loadClass(
                        ORACLE_JDBC_POOL_ORACLE_DATA_SOURCE).newInstance();
        Map propertyMap = new HashMap();
        // Instance property mapping koennte aus einer XML Datei kommen
        // Oder es wird vom Benutzer spezifiziert.
        propertyMap.put("user", user);
        propertyMap.put("password", password);
        propertyMap.put("serverName", serverName);
        propertyMap.put("portNumber", Integer.valueOf(portNumber));
        propertyMap.put("databaseName", databaseName);
        propertyMap.put("driverType", driverType);
        setInstanceProperties(oracleDataSource, propertyMap);
        return oracleDataSource;
    }

    private static void setInstanceProperties(Object instance, Map propertyMap)
            throws Exception {
        BeanInfo beanInfo = Introspector.getBeanInfo(instance.getClass());
        PropertyDescriptor[] propertyDescriptors = beanInfo
                .getPropertyDescriptors();
        for (int i = 0; i < propertyDescriptors.length; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();
            if (propertyMap.containsKey(propertyName)) {
                descriptor.getWriteMethod().invoke(
                        instance,
                        new Object[] { propertyMap.get(propertyName) });
            }
        }
    }
}

Gruss Tom
 
Naja einfach ist relativ, und nicht immer der beste Lernweg.
Du wirst anhand weiterer Postings (von mir) sehen wie einfach ich
es finden werde;).
Aber ich bin schon zufrieden, dass es einen gibt, der mal eine Antwort auf meine Frage hat.
 
Soooo....
Ich hab mich jetzt mal mit dem Beispiel von dir befasst. @ Thomas
Ich komm da im allgeimeinen noch nicht so wirklich klar.
Ich verstehe nicht ganz was du da machst.
Kannst du mir das etwas näher erklären, oder hast du vielleicht ein Tutorial dazu?
Kann ich denn mit der Herangehensweise das ganze auch dynamisch halten?...
Soll meinen:
Der Benutzer richtet eine neue Verbindung in meinem Programm ein. Und mein Prog schaut gleich mal nach, ob es 1. den Server gibt(das soll mal nicht das Prob werden) und 2. welchen Treiber das Prog bräuchte, um eine voll funktionsfähige Verbindung auf zu bauen.
Geht das?
 
Uuuudelellie!

Auch wenn sich die Sache längst erledigt haben sollte, möchte ich doch ein paar Leidensgenossen, die sich ebenfalls jetzt erst mit diesem Thema beschäftigen meinen Lösungsweg nicht vorenthalten. Man stößt bei Google doch immer wieder auf diesen Thread.

Thomas Lösung ist zwar sehr geschickt aber ich weiß nicht, ob es so gut ist eine Methode, die den Access Modifier protected hat, namentlich "addURL" mittels der reflect API accessible zu machen. Bin kein Experte und lasse mich gerne eines Besseren belehren.

Man könnte doch eher die Methode loadClass("package.classname") des URLClassLoaders verwenden:

Code:
import java.sql.DriverManager;
import java.net.URLClassLoader;
import javax.sql.DataSource;
import java.lang.reflect.*;

public class ClassLoaderTest{
	public static void main(String[] args) throws InstantiationException, ClassNotFoundException, java.net.MalformedURLException, IllegalAccessException {		

		java.net.URL p = new java.net.URL("file:\\C:\\Programme\\MySQL\\MySQL Tools for 5.0\\java\\lib\\mysql-connector-java-5.0.4-bin.jar");

		URLClassLoader loader = new URLClassLoader(new java.net.URL[]{p}, Thread.currentThread().getContextClassLoader() );		

		DataSource ds = (DataSource) loader.loadClass("com.mysql.jdbc.jdbc2.optional.MysqlDataSource").newInstance();

		try{
			Method meth = ds.getClass().getDeclaredMethod("setUser", new Class[]{ String.class });

			meth.invoke(ds, new Object[] { "Halloroot" });

			meth = ds.getClass().getDeclaredMethod("getUser", new Class[]{  });

			System.out.println( meth.invoke(ds, new Object[0]) );
		}catch( NoSuchMethodException ex ){
			System.out.println(ex.getMessage());
		}catch( InvocationTargetException ex ){
			System.out.println(ex.getMessage());
		}
	}
}

Erläuterungen:

WICHTIG: Ich habe es bisher nur für einen Connector (Mysql) getestet und auch noch keine Connection hergestellt. Werde mich nochmal melden, wenn ich mehrere ausprobiert habe.

Man muss die Methoden setUser, setPort etc... mittels der java.lang.reflect.Method aufrufen, da die Methoden im Interface javax.sql.DataSource nicht vorgeschrieben wurden, man aber nur eine gültige Connection von der DataSource bekommen kann, wenn diese Attribute alle gesetzt sind.

Die Nutzung von beans, wie bei Thomas Lösung zu sehen, ist wohl die von Java bevorzugte um die Methoden einer DataSource aufzurufen. (Scheint nebenbei bemerkt auch die elegantere Variante zu sein)

Ich verstehe nur nicht ganz warum man die Methoden nicht einfach im Interface vorgschrieben hat, damit die Methoden nach Instanzierung zur Verfügung stehen. Aber auch hier lasse ich mich gerne eines besseren belehren :)

Gruß,

Schlafor
 
Zuletzt bearbeitet:
Zurück