ODBC-Treiber

Uuudelellieee!

Warum die Methoden nicht im Interface vorgeschrieben wurden weiß ich jetzt. Es gibt so etwas wie eine Naming and Directory (JNDI) API. Damit kann man wohl einen Service / Dienst bereitstellen, der die zur Verbindungsherstellung notwendigen Daten bereitstellt.

Wenn ein Client sich nun bei der Datenbank anmelden möchte, muss man nur noch diese Daten beim Service erfragen und kann daraus direkt eine DataSource erstellen.

Code:
InitialContext ctx = new InitialContext();
DataSource s = (DataSource) ctx.lookup("jdbc/ServiceName");
Connection con = s.getConnection( user, pass );

Das hat den Vorteil, dass man bei Änderung der Datenbank nicht jeden Client anfassen, sondern die Änderungen nur in den Daten vornehmen muss, die durch den Service angeboten werden.

Egal, mir war das mit der protected Methode wichtig.

Hier nochmal für MySQL mit gültiger Connection, nur damit die ganze Sache abgerundet wird:

Code:
public static void main(String[] args) throws InstantiationException, ClassNotFoundException, java.net.MalformedURLException, IllegalAccessException, java.sql.SQLException {		

		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[] { "AAAA" });

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

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

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

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

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

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

			java.sql.Connection con = ds.getConnection();

			System.out.println( con.isValid(10) );

		}catch( NoSuchMethodException ex ){
			System.out.println("Methode nicht gefunden " + ex.getMessage());
		}catch( InvocationTargetException ex ){
			System.out.println(ex.getMessage());
		}
	}

Aber das mit dem Service will ich jetzt auch nochmal ausprobieren :).
 
Zuletzt bearbeitet:
Uuuudelelliiiieee!

Ich habe mit JNDI mal etwas rumprobiert und bin zum Entschluss gekommen, das es sich für mich nicht lohnt einen solchen Aufwand zu betreiben. (Auch wenns vom ursprünglichen Thema abweicht).

Hier findet sich ein ausführliches Tuorial: http://java.sun.com/products/jndi/tutorial/getStarted/overview/index.html

Ich mache es auf jeden Fall wie oben beschrieben.

Einfach wie oben über ein URL-Objekt der Treiber von einem Webserver herunterladen. Die benötigten Pfade (Datasource Path innerhalb des Treibers / Jars) ebenfalls vom Webserver laden und man kann die DataSource selbst erstellen.
 
JNDI-Tutorial - Nachtrag, ums zu komplettieren

http://java.sun.com/products/jndi/tutorial/

eignet sich für Systemlandschaften, in denen die DataSource über einen Applikationsserver und ein JNDI-konformes Protokoll wie LDPA bereitgestellt wird.

Dann hat man gegenüber Thomas bzw. meiner Lösung den Vorteil, dass nicht der gesamte Treiber über das Netzwerk übertragen werden muss. Auch wenns nur einmal für den Client bei Startup der Applikation vorgenommen werden muss.

Mit JNDI kann man die DataSource-Klasse einzeln übergeben und sie muss beim Client auch nicht mehr mittels ClassLoadern geladen werden. Ein DataSource-Objekt wird einfach auf dem Applikationsserver mittels JNDI an eine URL gebunden, die dann vom Client abgerufen werden kann.

Das kommt auch dem pooling von Verbindungen zugute, dass dann ebenfalls auf dem Server realisiert werden kann.

Hier eine kleine Sammlung interessanter Links:
Beispiele 5 und 6 im Skript
http://www.jeckle.de/vorlesung/DB-Anwendungen/script.html#jdo

JavaClassLoader - sehr theoretisch
http://it-republik.de/jaxenter/artikel/Java-Classloader-1261.html

dynamisches Laden von DB-Treiber mit ClassLoader und DriverManager, also ohne DataSource
http://www.kfu.com/~nsayer/Java/dyn-jdbc.html

Nochmal ClassLoader in Verbindung mit *.jar-Archiven
http://www.javaworld.com/javaworld/javatips/jw-javatip70.html


Wenn ich darf, würde ich das ganze dann als erledigt markieren.
 
Zuletzt bearbeitet:
Hallo,

danke für die Ausführungen. Das hättest du auch ruhig in einen eigenen Thread packen können ;-.)

Dann hat man gegenüber Thomas bzw. meiner Lösung den Vorteil, dass nicht der gesamte Treiber über das Netzwerk übertragen werden muss. Auch wenns nur einmal für den Client bei Startup der Applikation vorgenommen werden muss.
Also bei keiner der aufgezeigten Beispiele wird irgend einer Treiber übers Netzwerk geladen...

Mit JNDI kann man die DataSource-Klasse einzeln übergeben und sie muss beim Client auch nicht mehr mittels ClassLoadern geladen werden. Ein DataSource-Objekt wird einfach auf dem Applikationsserver mittels JNDI an eine URL gebunden, die dann vom Client abgerufen werden kann.
Das Stimmt so nicht ganz. Die datasources die über das JNDI verwaltet werden, spricht man in der Praxis nur innerhalb des selben Containers an. Entfernte Clients ziehen sich nicht die DataSource von einem anderen Rechner... das ginge auch nicht ohne weiteres denn die DataSource ist nicht serialisierbar. Weiterhin geht man eher den Weg den Datenbankzugriff von den Clients zu abstrahieren, so dass diese so "low-level" Persistenz Details wie eine DataSource gar nicht zu Gesicht bekommen.

Gruß Tom
 
Uuuudelellieeee!

stimmt. Die Clients holen sich ja nur die Daten beim Applikationsserver ab. Vielen Dank für den Hinweis :). Es würde ja das Konzept ad absurdum führen die dataSource zu liefern. Ich bin nur so in meiner Lösung drin, dass ich da was verwechselt habe :-( (siehe unten).

Wie gesagt, bin kein Experte und habe grad erst begonnen mich in Java und Datenbanken einzuarbeiten. :confused:

Tom: "Also bei keiner der aufgezeigten Beispiele wird irgend einer Treiber übers Netzwerk geladen..."

Sry, ich hatte mir kurz bevor ich die Nachricht verfasst habe eine Lösung mit einem Apachen gebastelt und vergessen zu posten.

Aber das lässt sich ja nachholen:

Code:
public static void main(String[] args) throws InstantiationException, ClassNotFoundException, java.net.MalformedURLException, IllegalAccessException, java.sql.SQLException {		

        // Habe diese URL mittels ALias in den HTML-Baum des Apachen eingebunden ->
        // physischer Pfad auf den DB-Treiber: C:\Programme\Apache Software
        // Foundation\Apache2.2\htdocs\connector\jdbc\mysql-connector-java-5.1.6-bin.jar        
        /*
         * Dort liegt dann also der DB-Treiber als jar
         */
        java.net.URL p = new java.net.URL("http://localhost/connector/jdbc");

        // Der ClassLoader lädt den Treiber nach, weil das *.jar ja nicht auf dem Client zur Verfügung steht und
        // der Treibr somit auch nicht in der CLASSPATH-Umgebungsvariable des Clients nicht bekannt ist
        // Es scheint wichtig zu sein, welchen ClassLoader man dem URLClassLoader im Konstrukt übergibt.
        // Ganz durchgestiegen bin ich da aber nicht. Egal einfach den ClassLoader des aktuellen Threads nehmen und gut. Danke an Tom.
        URLClassLoader loader = new URLClassLoader(new java.net.URL[]{p}, Thread.currentThread().getContextClassLoader() );

        // DataSource ist das Interface und in der loadClass() wird der Klassenpfad zur MysqlDataSource angegeben
        // dann instanzieren e volia
        DataSource ds = (DataSource) loader.loadClass("com.mysql.jdbc.jdbc2.optional.MysqlDataSource").newInstance();

        // So hier fehlen mir noch ein paar Grundlagen in Java:
        // Warum ist das Objekt von der Klasse MysqlDataSource, wenn ich vorher Cast nach DataSource ausgeführt habe
        // Ich meine man kann ja auch hinterher nach MysqlDataSource zurückcasten, die Infornmationen gehen bei cast ja nicht verloren
        // Trotzdem dürften die weiter unten mittels java.lang.reflect.Method aufgerufenen Methoden nicht zur Verfügung stehen.
        System.out.println(ds.getClass());
                 
        try{                     
                Method meth = ds.getClass().getDeclaredMethod("setUser", new Class[]{ String.class });
                                
                meth.invoke(ds, new Object[] { "root" });

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

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

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

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

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

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

                // Ganz normal eine Verbindung holen
                java.sql.Connection con = ds.getConnection();

                // Prüfen ob die Verbindung gültig ist
                System.out.println( con.isValid(10) );

        }catch( NoSuchMethodException ex ){
                System.out.println("Methode nicht gefunden " + ex.getMessage());
        }catch( InvocationTargetException ex ){
                System.out.println(ex.getMessage());
        }

        java.sql.Connection con = ds.getConnection();

        System.out.println( con.isValid(10) );
                
     }

Nur damit der ganze Schmu, den ich hier fabriziere besser nachvollziehbar ist:

Ich bastle mir gerade einen Java-DB-Client (nicht nur, kommt auch noch Logik dazu, die Berechnungen vornimmt) der stand-alone, also ohne Appl auskommen soll. Hatte ehrlich gesagt gar nicht dran gedacht als ich begonnen habe. Soll halt alleine ohne großen Aufwand für den Nutzer lauffähig sein.

Aber jetzt komm ich immer mehr zu dem Schluss ein Applet zu schreiben. Nur dann brauch ich ja auch wieder nen Server!?
 
Zuletzt bearbeitet:
Uuuudelelliieeeee!

Jetzt hätte ich noch ein Frage:

Wo ist festgelegt wie die Attribute der DataSource-Implementierung benannt werden?

Wenn ich mir mittels PropertyDescriptor die Attributnamen aus der zur DataSource zugehörigen BeanInfo-Implementierung hole, erhalte ich beispielsweise für den Namen des Servers die Attributbezeichnung:

"serverName" (als Wert beispielsweise "localhost")

Kann man sich darauf verlassen, dass die Attributbezeichnungen bei allen DB-Herstellern gleich sind oder ist der Servername beim einen so und beim anderen anders. Bsp.:

"server" = "localhost"

Oder ist die DataSource generell nur über einen Context zu laden, bei dem ja dann eine fertig konfigurierte DataSource registriert und "zurückgeliefert" wird. (Ich weiß, sie wird nicht wirklich zurückgeliefert )

Wäre über Hilfe sehr dankbar :).

Gruß

Schlafor
 
Uuudelelliiiieeee!

Antwort ist ja, es gibt einen Standard.

Hier ein kleiner Vorgeschmack, aber das ist ja nur für Oracel.

http://stanford.edu/dept/itss/docs/oracle/10g/java.101/b10979/urls.htm

Table 3-1 Standard Datasource Properties enthält die Standard-Properties. Und Oracel ignoriert laut dieser Quelle schonmal unverblühmt ein Stadard-Property :).Sehr gut :rolleyes:!

"Be aware, however, that Oracle does not implement the standard roleName property."

Und die vollständige Spezifikation zur JDBC2-API findet sich unter:

http://java.sun.com/products/jdbc/download.html

Seite 12 unten werden dann auch die Standardattribute der DataSource beschrieben.

Gruß

Schlafor
 
Tja Unwissender :).

Das ist aus Walt Disneys Robin Hood. Auch wenns kindisch ist, man sollte beim Programmieren immer was zum Lachen haben.

Ich stehe dazu, der Film ist einfach nur geil. Ist zwar ein Kinderfilm aber ich habe ihn mir nochmal mit meinen Kollegen angesehen und mich weggeschrien.

Hatte ihn jedoch bereits als Kind geshen == Nostaligie.

Uuuuuhhudellleiiieeeeeeeee:)
 
Zurück