Einige Probleme treten öfters mit MySQL Connector/J auf. Dieser Abschnitt beschreibt die Symtome und ihre Heilung.
Questions
25.3.5.3.1: Wenn ich mit MySQL Connector/J eine Datenbankverbindung aufbaue, wird folgende Ausnahme ausgelöst:
SQLException: Server configuration denies access to data source SQLState: 08001 VendorError: 0
Was ist da los? Mit dem Kommandozeilen-Client von MySQL funktioniert die Verbindung einwandfrei.
25.3.5.3.2: Meine Anwendung löst die SQLException 'No Suitable Driver' aus. Warum?
25.3.5.3.3: Ich versuche, MySQL Connector/J in einem Applet oder einer Anwendung einzusetzen und bekomme einen Fehler wie diesen gemeldet:
SQLException: Cannot connect to MySQL server on host:3306. Is there a MySQL server running on the machine/port you are trying to connect to? (java.security.AccessControlException) SQLState: 08S01 VendorError: 0
25.3.5.3.4: Ich habe ein Servlet/Programm, das es einen Tag lang tut und dann über Nacht nicht mehr funktioniert
25.3.5.3.5: Ich versuche, aktualisierbare Ergebnismengen von JDBC-2.0 einzusetzen, und eine Fehlermeldung behauptet, meine Ergebnismenge sei gar nicht aktualisierbar.
Questions and Answers
25.3.5.3.1: Wenn ich mit MySQL Connector/J eine Datenbankverbindung aufbaue, wird folgende Ausnahme ausgelöst:
SQLException: Server configuration denies access to data source SQLState: 08001 VendorError: 0
Was ist da los? Mit dem Kommandozeilen-Client von MySQL funktioniert die Verbindung einwandfrei.
MySQL Connector/J muss für die Verbindung mit MySQL TCP/IP-Sockets einsetzen, da Java keine Unix Domain Sockets unterstützt. Der Sicherheitsmanager von MySQL schaut deshalb bei einem Verbindungsversuch mit MySQL Connector/J in seine Berechtigungstabellen, um festzustellen, ob die Verbindung zulässig ist.
Damit das funktionieren kann, müssen Sie dem MySQL-Server
mithilfe der GRANT
Anweisung die
notwendigen Sicherheitszeugnisse vorweisen. Weitere
Informationen siehe
Abschnitt 13.5.1.3, „GRANT
und REVOKE
“.
Hinweis.
Ein Verbindungstest mit dem Kommandozeilenclient
mysql funktioniert nur, wenn Sie das
Flag --host
hinzufügen und als Host
etwas anderes als localhost
einsetzen. Der Kommandozeilenclient
mysql wird Unix-Domain-Sockets
verwenden, wen Sie den speziellen Hostnamen
localhost
benutzen. Um die Verbindung
mit localhost
zu testen, müssen Sie
stattdessen 127.0.0.1
als Hostnamen
einsetzen.
Warnung. Wenn Sie bei der Änderungen von Berechtigungen in MySQL Fehler machen, kann dies dazu führen, dass Ihre Serverinstallation keine optimalen Sicherheitseigenschaften mehr hat.
25.3.5.3.2: Meine Anwendung löst die SQLException 'No Suitable Driver' aus. Warum?
Für diesen Fehler gibt es drei mögliche Gründe:
Der Connector/J-Treiber liegt nicht in Ihrem
CLASSPATH
, siehe auch
Abschnitt 25.3.2, „Installation von Connector/J“.
Der Verbindungs URL hat ein falsches Format oder Sie referenzieren den verkehrten JDBC-Treiber.
Die Systemeigenschaft jdbc.drivers
wurde bei Benutzung des DriverManager nicht auf das
Verzeichnis des Connector/J-Treibers eingestellt.
25.3.5.3.3: Ich versuche, MySQL Connector/J in einem Applet oder einer Anwendung einzusetzen und bekomme einen Fehler wie diesen gemeldet:
SQLException: Cannot connect to MySQL server on host:3306. Is there a MySQL server running on the machine/port you are trying to connect to? (java.security.AccessControlException) SQLState: 08S01 VendorError: 0
Entweder führen Sie ein Applet aus, oder Ihr MySQL-Server wurde mit der Option "--skip-networking" installiert, oder Ihr MySQL-Server sitzt hinter einer Firewall.
Applets können Netzwerkverbindungen nur mit dem Computer aufnehmen, auf den der Webserver läuft, der die .class-Dateien des Applets liefert. Das bedeutet, dass MySQL ebenfalls auf demselben Computer laufen muss (es sei denn, Sie verwenden irgendeine Art von Port-Umleitung). Außerdem bedeutet es, dass Sie Applets nicht in Ihrem lokalen Dateisystem testen können, sondern immer erst auf einem Webserver installieren müssen.
MySQL Connector/J kann mit MySQL nur über TCP/IP kommunizieren, da Java keine Unix-Domain-Sockets unterstützt. Die TCP/IP-Kommunikation mit MySQL kann jedoch in Mitleidenschaft gezogen werden, wenn MySQL mit der Option "--skip-networking" gestartet wurde oder hinter einer Firewall sitzt.
Wenn MySQL mit der Option "--skip-networking" gestartet
wurde (dies tut beispielsweise das Debian Linux-Package
von MySQL Server), müssen Sie dies in der Datei
/etc/mysql/my.cnf or /etc/my.cnf auskommentieren.
Natürlich kann Ihre my.cnf-Datei auch im
data
-Verzeichnis Ihres MySQL-Servers
oder irgendwo sonst liegen (je nachdem, wie MySQL für Ihr
System kompiliert wurde). Binärversionen von MySQL AB
schauen immer in /etc/my.cnf and [datadir]/my.cnf. Wenn
Ihr MySQL-Server durch eine Firewall geschützt ist,
müssen Sie diese so konfigurieren, dass sie
TCP/IP-Verbindungen von dem Host, auf dem der Java-Code
läuft, zu dem MySQL-Server auf dem Port zulässt, auf den
MySQL lauscht (nach Voreinstellung 3306).
25.3.5.3.4: Ich habe ein Servlet/Programm, das es einen Tag lang tut und dann über Nacht nicht mehr funktioniert
MySQL schließt Verbindungen, die 8 Stunden lang inaktiv waren. Sie müssen entweder einen Verbindungspool, der alte Verbindungen behandelt, oder den "autoReconnect"-Parameter verwenden (siehe Abschnitt 25.3.4.1, „Driver/Datasource-Klassennamen, URL-Syntax und Konfigurationseigenschaften für Connector/J“).
Außerdem sollten Sie SQLExceptions in Ihrer Anwendung
abfangen und behandeln, anstatt sie immer weiter
durchzureichen, bis Ihre Anwendung abbricht; schon allein
weil es guter Stil ist. MySQL Connector/J stellt den
SQLState (siehe
java.sql.SQLException.getSQLState()
in
Ihren APIDOCS) auf "08S01" ein, wenn es während der
Verarbeitung einer Anfrage Netzwerkprobleme bekommt. Ihr
Anwendungscode sollte dann versuchen, sich erneut mit
MySQL zu verbinden.
Das folgende (vereinfachte) Beispiel zeigt, mit welchem Code man solche Ausnahmen behandeln könnte:
Beispiel 25.12. Beispiel einer Transaktion mit Retry-Logik
public void doBusinessOp() throws SQLException { Connection conn = null; Statement stmt = null; ResultSet rs = null; // // Wie oft wollen Sie die Transaktion erneut versuchen // (oder wenigstens eine Verbindung zu bekommen)? // int retryCount = 5; boolean transactionCompleted = false; do { try { conn = getConnection(); // wir setzen voraus, dass diese von einer // javax.sql.DataSource oder dem // java.sql.DriverManager geliefert wird conn.setAutoCommit(false); // // An diesem Punkt hängt die 'Retry-Fähigkeit' der // Transaktion von Ihrer Anwendungslogik ab und davon // ob Sie Autocommit verwenden (in diesem Fall nicht) // und ob Sie transaktionssichere Speicher-Engines // einsetzen // // Für dieses Beispiel gehen wir davon aus, das es _nicht_ sicher ist, // die gesamte Transaktion erneut zu versuchen, und setzen daher // die Retry-Zahl auf 0 // // Wenn Sie nur transaktionssichere Tabellen verwenden oder // Ihre Anwendung sich davon erholen könnte, wenn eine Verbindung // mitten in der Operation abstürzt, dann würden Sie hier am // 'retryCount' nichts ändern und die Schleife einfach so lange durchlaufen, // bis retryCount == 0. // retryCount = 0; stmt = conn.createStatement(); String query = "SELECT foo FROM bar ORDER BY baz"; rs = stmt.executeQuery(query); while (rs.next()) { } rs.close(); rs = null; stmt.close(); stmt = null; conn.commit(); conn.close(); conn = null; transactionCompleted = true; } catch (SQLException sqlEx) { // // Die beiden 'Retry-fähigen' SQL-Zustände sind 08S01 // für einen Kommunikationsfehler und 40001 für Deadlock. // // Retry nur dann, wenn der Fehler wegen einer alten Verbindung, // Kommunikationsproblemen oder einem Deadlock auftrat // String sqlState = sqlEx.getSQLState(); if ("08S01".equals(sqlState) || "40001".equals(sqlState)) { retryCount--; } else { retryCount = 0; } } finally { if (rs != null) { try { rs.close(); } catch (SQLException sqlEx) { // Das gehört ins Log. . . } } if (stmt != null) { try { stmt.close(); } catch (SQLException sqlEx) { // Das gehört ebenfalls ins Log. . . } } if (conn != null) { try { // // Wenn hier conn nicht Null ist, sollte die // Transaktion zurückgerollt werden, da noch // nicht alle Arbeit erledigt ist try { conn.rollback(); } finally { conn.close(); } } catch (SQLException sqlEx) { // // Wenn hier eine Ausnahme auftritt, ist es ernst. // Daher reichen wir sie besser im // Stapel nach oben anstatt sie nur // zu protokollieren . . . throw sqlEx; } } } } while (!transactionCompleted && (retryCount > 0)); }
Hinweis.
Die Option autoReconnect
wird nicht
empfohlen, da es keine sichere Methode einer
Neuverbindung mit dem MySQL-Server ohne das Risiko von
Schäden am Verbindungszustand oder den
Datenbankzustandsinformationen gibt. Nutzen Sie
stattdessen einen Verbindungspool, der Ihre Anwendung in
die Lage versetzt, eine verfügbare Verbindung aus dem
Pool zur Kontaktaufnahme mit dem MySQL-Server zu
benutzen. Die autoReconnect
-Facility
ist veraltet und wird in einem zukünftigen Release
wahrscheinlich abgeschafft werden.
25.3.5.3.5: Ich versuche, aktualisierbare Ergebnismengen von JDBC-2.0 einzusetzen, und eine Fehlermeldung behauptet, meine Ergebnismenge sei gar nicht aktualisierbar.
Da MySQL keine Zeilenbezeichner kennt, kann MySQL Connector/J Ergebnismengen nur dann aktualsieren, wenn sie von Anfragen auf Tabellen herrühren, die mindestens einen Primärschlüssel haben. Außerdem muss die Anfrage jeden Primärschlüssel auswählen und darf sich nur auf eine einzige Tabelle beziehen (also keine Joins). Dies ist in der JDBC-Spezifikation festgelegt.
Dies ist eine Übersetzung des MySQL-Referenzhandbuchs, das sich auf dev.mysql.com befindet. Das ursprüngliche Referenzhandbuch ist auf Englisch, und diese Übersetzung ist nicht notwendigerweise so aktuell wie die englische Ausgabe. Das vorliegende deutschsprachige Handbuch behandelt MySQL bis zur Version 5.1.