JDBC-Treiber installieren

javaDeveloper2011

Erfahrenes Mitglied
Hallo,

Ich habe eine funktionierende MySQL-Datenbank als Workbench-File erstellt, diese möchte ich jetzt mit einer Java-Applikation bzw. mit einem Applet verbinden. Ich habe den JDBC-Driver von der MySQL Seite http://www.mysql.de/downloads/connector/j/ heruntergeladen, will ich aber mit
"Class.forName("com.mysql.jdbc.Driver").newInstance();"
auf den Treiber zugreifen, findet BlueJ die Klasse nicht und es erscheint folgende Fehlermeldung:
java.lang.NoClassDefFoundError: com/mysql/jdbc/ConnectionImpl
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:305)
at java.sql.DriverManager.getConnection(DriverManager.java:582)
at java.sql.DriverManager.getConnection(DriverManager.java:185)
at DatenbankVerbindung.driver(DatenbankVerbindung.java:13)
Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.ConnectionImpl
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:305)
at java.sql.DriverManager.getConnection(DriverManager.java:582)
at java.sql.DriverManager.getConnection(DriverManager.java:185)
at DatenbankVerbindung.driver(DatenbankVerbindung.java:13)
at __SHELL0.run(__SHELL0.java:6)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at bluej.runtime.ExecServer$3.run(ExecServer.java:774)

Wie kann ich also jetzt den Treiber so installieren, dass BlueJ ihn findet?
Ich freue mich auf kompetente Hilfe!
 
Wilkommen hier im Forum!

Wo liegt denn der Treiber für MySQL?
Im selben Verzeichnis wie deine Klassen?

Übrigens: wenn du deinen Code und die Exceptions in die dafür vorhergesehenen Tags einfügst, liest sich das leichter ;)
 
Hallo,

erstmal vielen dank für die Antwort!

Ich habe die Lösung aber mittlerweile selbst gefunden:
- Wenn man von allen Projekten auf die Treiberklasse zugreifen will, muss
mysql-connector-java-5.1.15-bin
im Verzeichnis C:\Program Files\Java\jdk1.6.0_21\jre\lib\ext liegen.
- Außerdem brauch man einen Datenbankserver auf dem localhost (Download von http://dev.mysql.com/downloads/mirror.php?id=401203#mirrors
- Um die die Datenbank auch wirklich auf dem MySQL-Server zu speichern, ist es am besten sie aus der NetBeans IDE heraus anzulegen und mit der Java-Applikation zu verbinden
- Mein Projekt funktioniert jetzt schon fast einwandfrei!!
 
ich hätte noch eine weitere lösung für dein problem

java hat beim laden von JDBC treibern das problem das zum zeitpunkt des VM starts der entsprechende treiber schon im classpath liegen muss ...

und trotzdem kann man JDBC trieber dynamisch auch während der runtime laden

der trick : eine DummyDriver klasse ...
diese dummy-klasse wird von java.sql.Driver abgeleitet und leitet alle methoden an den geladenen treiber weiter

das ganze funktioniert in etwa so :
die dummy-klasse erhält einen konstruktur nach folgenden schema
Java:
public DummyDriver(Driver driver) { this.driver=driver; }
die dummy-klasse hat eine private deklaration einer driver-instanz ... also
Java:
private Driver driver=null;
nun halt alle methoden implementieren und als return einfach die mehtode auf den eigentlich driver anwenden

damit das nun funktioniert muss dieser dummy-treiber mit in das jar welches zum start geladen wird *bei einem APPLET halt in das MAIN-jar*
nun kann man ganz locker mit einem URLClassLoader eine java.sql.Driver instanz erzeugen und an den drummydriver übergeben und diesen dann beim drivermanager anmelden

wenn man sich nun über den drivermanager eine liste ausgeben lässt bekommt man nun entsprechend viele einträge der dummydriver klasse ...


diese lösung habe ich beim selben problem letztes jahr im frühling durch google gefunden ... leider ist es mir jetzt nicht möglich durch entsprechende suchbegriffe diese seite zu finden ... es kann sein das der eintrag aus der google liste gelöscht wurde ... wäre sehr schade
ich habe auch versucht hier auf tutorials und auch im java-forum.org zu finden ... leider war die lösung nicht dabei ...
eine beispiel implementation habe ich jetzt leider nicht zur hand da ich zur zeit im krankenhaus liege und nicht an die daten von meinem rechner daheim komme ...
sollte aber nicht schwer das geschrieben hier umzusetzen ...
ich poste nachher mal nach tests eine lauffähige variante
 
Zuletzt bearbeitet von einem Moderator:
so .. habe jetzt ohne erfolg bei der suche gehabt zu haben schnell den DummyDriver lauffähig zusammen geschrieben

Java:
import java.io.*;
import java.net.*;
import java.sql.*;
import java.util.*;
import java.util.logging.*;
public class DummyDriver implements Driver
{
	private Driver driver=null;
	public DummyDriver() { }
	public DummyDriver(Driver driver) { this.driver=driver; }
	public boolean acceptsURL(String url) throws SQLException { return driver.acceptsURL(url); }
	public Connection connect(String url, Properties info) throws SQLException { return driver.connect(url, info); }
	public int getMajorVersion() { return driver.getMajorVersion(); }
	public int getMinorVersion() { return driver.getMinorVersion(); }
	public Logger getParentLogger() throws SQLFeatureNotSupportedException { return driver.getParentLogger(); }
	public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { return driver.getPropertyInfo(url, info); }
	public boolean jdbcCompliant() { return driver.jdbcCompliant(); }
}

um jetzt einen treiber laden zu können muss man bereits eine instanz dessen referrenziert haben
beispiel mit MySQL

Java:
import java.io.*;
import java.net.*;
import java.sql.*;
import java.util.*;
public class JDBCTest
{
	public static void main(String[] args) throws Exception { new JDBCTest(); }
	public JDBCTest() throws Exception
	{
		URLClassLoader cl=new URLClassLoader( new URL[] { (new File("mysql-connector-java-5.1.15-bin.jar")).toURI().toURL() } );
		Object o=cl.loadClass("com.mysql.jdbc.Driver").newInstance();
		DriverManager.registerDriver(new DummyDriver((Driver)o));
		Enumeration<Driver> e=DriverManager.getDrivers();
		while(e.hasMoreElements())
		{
			Driver driver=e.nextElement();
			System.out.println(driver.getClass().getName());
			System.out.println(driver.acceptsURL("jdbc:mysql://localhost:3306/mysql"));
		}
	}
}

ausgabe

Code:
PROPMT>java JDBCTest
sun.jdbc.odbc.JdbcOdbcDriver
false
DummyDriver
true

PROMPT>java -cp .;mysql-connector-java-5.1.15-bin.jar JDBCTest
sun.jdbc.odbc.JdbcOdbcDriver
false
com.mysql.jdbc.Driver
true
DummyDriver
true

PROMPT>

beim ersten mal ohne explizite angabe des connector-jars ... es wird nur der DummyDriver geladen
beim zweiten mal mit angabe des jars ... der MySQL-JDBC-Driver ist nun zum start der vm verfügbar und wird automatisch geladen und angemeldet ... *siehe source : keine anmeldung des mysql-drivers*

zu sehen hier ganz eindeutig das über einen URLClassLoader WÄHREND der runtime der treiber geladen und referrenziert wird ...
viele denken jetzt : ja aber durch newInstance() müsste sich der treiber doch automatisch anmelden ...
NEIN ... grund : *siehe vorpost*
und wenn sich jetzt der treiber schon in meinem classpath befindet ?
dann muss NICHTS gemacht werden ... selbst ein aufruf von Class.forName() kann man sich sparen da wie gesagt java zum start automatisch alle verfügbaren JDBC treiber läd ...
macht man mal die probe und lässt sich dann die registrierten treiber ausgeben so sieht man das man mit einem aufruf von Class.forName() oder Class.newInstance() den treiber doppelt registriert ...
wenn aber wie gesagt der treiber nicht im classpath liegt sondern erst zur runtime geladen wird muss man die einschränkung das java nur treiber-klassen akzeptiert die zum vm start verfügbar sind ... und genau das erreichen wir jetzt durch unseren DummyDriver

der DummyDriver stellt keinen eigenen Driver dar da weder ein static-block vorhanden ist noch der neutrale konstruktor irgendetwas macht ...
erst durch den aufruf mit übergabe eines validen treibers wird die klasse nutzbar ...
natürlich kann man dieses spiel so oft verketten wie man will ... also dem DummyDriver eine weitere DummyDriver-instanz übergibt oder halt einen anderen dummy der spezielle treiber castet und dadurch erst für den DummyDriver verwendbar macht ...
da man nur eine weitere Driver-instanz erhält wenn man zum beispiel die eben erstellt instanz welche als Object gecastet ist übergibt ... also so : Driver dummy=new DummyDriver((Driver)object); ... oder entsprechend : Driver dummy=new DummyDriver((Driver)class.newInstance()); ... kann man so damit noch nicht viel anfangen ...
erst wenn man den nun erhaltenen validen Driver *dadurch das DummyDriver zum startzeitpunkt im classpath war *oder halt im gestartetem jar** explizit beim DriverManager anmeldet erhält man zugriff auf diesen und kann mit DriverManager.getConnection eine verbindung über den durch DummyDriver gecasteten externen Driver zur datenbank herstellen


wie gesagt : habe diese lösung letztes jahr auch nur durch google gefunden und hab mich bei diesem thema und beschriebenen problem sofort an meine fragen damals erinnert die ich hatte weil es halt par tu nicht klappen wollte ...
mir musste das auch erstmal einer erklären das java diese macke hat das nur treiber zulässig sind deren Driver klasse zum startzeitpunkt der vm verfügbar war ...
und um dir halt nun das problem abzunehmen das jar extra in in den lib-ordner der java-installation zu packen oder explizit im classpath anzugeben gebe ich dieses wissen natürlich weiter ...

unter anderem banne ich es damit auch auf tutorials fest ... falls also mal wieder wer googlet sollte er hier landen ...
 
Zuletzt bearbeitet von einem Moderator:
@Spike
Ich glaube deine Lösung schießt über das Ziel hinaus. Und ich verstehe den Sinn dahinter auch nicht ein Interface nochmal zu wrappen. Nun gut, wir wollen ja dem TE helfen zur Selbsthilfe.

Die erste Frage ist kobel==javaDeveloper2011?^^

Dann antworte ich mal auf kobel.
lib/ext zu verwenden ist imho ein schlechter Stil, da man hier die Abhängigkeit verschleiert.
Am einfachsten fügt man das jar zum Classpath hinzu (vlt in einem lib-Unterordner im Projekt). Wie man das unter Netbeans einstellt, kann ich dir leider nicht helfen, da ich eclipse benutzen. Jedoch solltest du mit Google oder Netbeans-Doku oder einfach nur durch rumstöbern auf die Lösung kommen :)

Bei komplexeren Abhängigkeiten kann man mal einen Blick auf maven werfen :)
 
@Anime

ja ... vielleicht schießt meine lösung drüber hinaus ...
aber muss zugeben : bin froh das ich das jetzt hier auf tutorials gebannt hab

zum wie du ihn nennst unnötigen wraper
das ding dient dazu eine "gültige" driver-klasse zum startzeitpunkt der vm zur verfügung zu stellen
grund : *wie oben beschrieben* es werden nur driver geladen/akzeptiert die zum start der vm auch über classpath angegeben und dadurch bekannt waren *wodurch dann das auto-load prinzip greift*
will man seine app aber nun als art plug-in system entwickeln oder unabhängig von irgendwelche classpath-manipulationen halten *z.b. auf user-systemen* so sind die dann "externen" treiber zum start der vm halt nicht bekannt und werden dadurch nicht geladen
ein späteres laden zur runtime schlägt dann ebenfalls fehl
nun greift mein wraper : er simuliert eine gültige treiber klasse die zum start der vm bekannt ist da sie z.b. im main-jar eingebunden ist ... diese klasse wird nun von der vm versucht durch den autoloader zu laden was ja erstmal nur in einer nicht bemerkbaren exception endet *mit der debug-option erhält man diese exception dann in der console*
allerdings bleibt die wraper-klasse als driver valid um z.b. später erneut geladen zu werden
wenn man nun an diesen wraper einen funktionierenden driver übergibt und jetzt versucht die wraper-klasse als driver zuladen funktioniert es da die wraper-klasse alle aufrufe an den darunterliegenden implementierten driver weiterreicht
da dieser sich jedoch in einer URLClassLoader-umgebung befindet wird somit das gesamte geladene jar eingebunden ... und nicht nur die driver-klasse des treibers selbst wodurch ja die exception ausgelöst wird das die IMPL-klasse nicht gefunden werden kann

und DAS ist der sinn dahinter ... einfach eine möglichkeit schaffen externe driver zur runtime erfolgreich zu laden ...


zum thema

wie bereits erwähnt ... es ist echt kein schöner stil das lib/ext/ verzeichnis zu benutzen ...
und schon garnicht um kompatibilität für ein applet bereitzustellen
das sollten wirklich nur apps machen die sich fest installieren und auch in der aktiven jre verankern können ... es nützt nichts dein JDK vollzustopfen wenn das system standard mäßig das JRE nutzt ... vice versa im umgekehrten fall

bei applets macht man es doch eigentlich generell das man entweder alles mit ins jar packt und dann inner manifest alles einträgt oder das mans im applet-tag mit angibt ...
also grade für applets versteh ich sowieso nicht warum du nicht diese standardisierten mittel nutz ...
was apps angeht : entweder wraper die den classpath setzen , im manifest angegeben oder halt über wraper-klassen wie mein beispiel für JDBC-driver

alles in allem is das problem eingentlich hier im grundlagen-forum richtig ... weil es wirklich eine grundlage ist zu wissen wie man JDBC-driver in den beiden fällen *applet / app* richtig angibt bzw ladefähig macht


wenn jetzt immer noch fragen kommen wie man es anderst löst ... z.b. ohne so system-bezogen an den jre-libs rumspielt ... dann kann ich hier nur vorsorglich antworten : alles notwendige wurde gesagt um deinen fehler zu lösen ohne diesen eingriff ins system ...

hoffe du schaffst es jetzt endlich dein applet wirklich fehlerfrei zum laufen zu bekommen
 
Hallo zusammen,

Ich hab mittlerweile alles zum laufen gekriegt und auch gemerkt das es auf anderen Rechnern natürlich nur geht wenn das jar mit dem Treiber im lib-Verzeichnis anstatt irgendwo im JRE liegt. Das war in einem Video leider falsch erklärt!

Trotzdem danke, SPiKEe für die viele mühe, vielleicht werde ich das dynamische laden bald für ein anderes Projekt brauchen.

javaDeveloper2011
 
Hmm ... naja für Developer mag das Video sicher gut sein ... und für uns ist es ja auch kein Problem mal ne Lib zu installieren weil wir alle wissen wie es geht ... aber jemand der davon keine Ahnung hat wird da sicher große Probleme bekommen.
Es freut mich aber das ich den DummyDriver dann doch nicht ganz sinnlos gepostet habe. Habe im übrigen mitlerweile auch den Original-Post von dem ich das habe wieder gefunden. Dort wurde es sogar mit Annotations gelöst das bei Java6 getParentLogger nicht mit compiled wird ... aber bei Java7 schon .. *kann mir mal wer erklären wie man in Java die Annotations als "Präprozessoren" wie bei C verwenden kann ?*

Was ich für ALLE noch anmerken will :

die Methode "public Logger getParentLogger()" gibt es erst ab Java7 *siehe Doc : "Since : 1.7"*
Wenn man diese Klasse also mit Java6 compilen will einfach diese Zeile als Comment kennzeichnen, ansonsten kommt ne Error-Meldung vom Compiler.
 

Neue Beiträge

Zurück