Teil 3 der MySQL-Serie

MySQL und Java: Datenabfrage

Christian Barthel

Lernen Sie in dieser Serie Schritt für Schritt den Zugriff auf eine MySQL-Datenbank mit Java. Neben dem Erstellen der Syntax der SQL-Abfrage geht es auch um das Einbinden eines JDBC-Treibers und das Schreiben geeigneter Abfrageklassen.

Einfache Datenabfrage

Da wir nun unsere Verbindung aufgebaut haben, können wir uns nun erste Datensätze aus der MySQL-Tabelle holen. Die gesamte Methode befindet sich hier unterhalb, die Erklärung folgt nach dem Listing.

public Vector loadCustomers(String table)
{ Statement stmt = null;
ResultSet result = null;
try {
stmt = connection.createStatement();
result = stmt.executeQuery("SELECT * FROM " + table);
result.first(); // <- first entry of the result set
// STEP 2: copy the data from the result set into the vector
Vector customers = new Vector();
	
while(! result.isAfterLast()) // as long as valid data is in the result set
{
int id = result.getInt("kid");
String name = result.getString("name");
String vorname = result.getString("vname");

Kunde kunde = new Kunde(id, name, vorname);
customers.add(kunde);
result.next(); // go to next line in the customer table
}

// STEP 3: return the vector containing the customer data
return customers;
} catch (Exception ex) {
System.out.println("Error during access + " + table + "n" + ex.getMessage());
return null;
}
}

Das Prinzip dieser Abfragemethode kann in sechs einfachen Schritten erklärt werden:

  • Die Methode loadCustomers wird mit dem Parameter „Tabellenname“ (Tabelle, die unsere Kunden enthält) aufgerufen.
  • Wir bauen die Verbindung auf und stellen unser SQL-Statement (ganz am Anfang wurde kurz darüber gesprochen, wie dieses aussehen muss, damit wir einfache Abfragen erstellen können)
  • Diese Abfrage wird ausgeführt und die Datensätze werden in einem „Resultset“ gespeichert.
  • Um nun einen Zugriff auf die tatsächlichen Datensätze aus dem Resultset zu bekommen, müssen wir in eine WHILE-Schleife den kompletten Datenbestand aus dem Resultset-Objekt „herausziehen“; in diesem Fall speichern wir diese „herausgezogenden“ Datensätze“ in einem Vektor ab
  • Ein Vector dient dazu – wie Arrays oder ArrayLists – Daten abzuspeichern
  • Den gesamten Vektor mit den Datensätzen geben wir als Rückgabewert der Methode zurück.

Abbildung 1

Gehen wir noch kurz den Code im Detail durch. Bevor wir den TRY/CATCH-Block initialisieren, legen wir zunächst unsere benötigten Variablen ab. Wir benötigen ein Statement (Variablenname stmt), auf dessen wir unsern SQL-Query ausführen können. Zusätzlich wollen wir die vom Datenbankserver gelieferten Daten auch abspeichern, dies geschieht innerhalb des ResultSet-Objekts.

Statement stmt = null;
ResultSet result = null;

Im nächsten Schritt benötigen wir einen TRY/CATCH-Block, um eventuell auftretende Ausnahmen abfangen zu können (falscher SQL-Query, Verbindungsabbruch, nicht vorhandene Datenfelder, …). Von der Instanzvariablen „connection“ lassen wir uns zunächst ein Statement geben. Die „connection“-Variable besitzt die Verbindungsdaten und baut mit diesen eine Verbindung auf.

try {
stmt = connection.createStatement();

Als Rückgabewert erhalten wir ein Statement-Objekt, auf dem wir unseren SQL-Query ausführen können. Der Methode executeQuery wid ein SQL-String übergeben, mit der wir entweder Daten abfragen, einfügen oder modifizieren können. In diesem Fall übergeben wir die statischen Schlüsselwörter „SELECT * FROM“, gefolgt von der Variable „table“, die den Tabellennamen der zu abfragenden Tabelle enthält. Eine deutsche Übersetzung dieses Befehls könnte in etwa so lauten: Gib mir alle Spalten aus der Tabelle „table“ ohne Einschränkung (keine WHERE-Dinge…). Der Tabellenname wird beim Methodenaufruf als Parameter initialisiert.

stmt = connection.createStatement();
result = stmt.executeQuery("SELECT * FROM " + table);

Das Rückgabeobjekt von „executeQuery“ ist ein ResultSet und beinhaltet alle zurückgelieferten Datensätze der Abfrage. Um es später benutzen zu können, speichern wir dieses ResultSet in der Variable „result“ ab.

Nun können wir mit dem Erstellen der Kundenobjekte beginnen. Zunächst wird der aktuelle Zeiger auf den ersten Datensatz gesetzt.

result.first(); // <- first entry of the result set
Vector customers = new Vector();

Danach können wir mit einer While-Schleife das ResultSet durchlaufen. Die Schleifenbedingung „isAfterLast“ läuft solange, bis der letzte Datensatz ausgeführt wurde.

Für jeden dieser Datensätze holen wir mit den getXXX-Methoden (wie beispielsweise getInt oder getString) und den dazugehörigen Spaltennamen die Daten heraus und legen ein neues Objekt vom Typ Kunde an (mit Kundennummer, Nachname und Vorname). Wichtig ist bei den getXXX-Methoden, dass hier der übergebene String mit dem Spaltennamen in der Datenbank übereinstimmen muss. Das erzeugte Kundenobjekt wird dem Vektor, der noch vor der WHILE-Schleife deklariert wurde, angefügt.

while(! result.isAfterLast())
{
int id = result.getInt("kid");
String name = result.getString("name");
String vorname = result.getString("vname");
	
Kunde kunde = new Kunde(id, name, vorname);
customers.add(kunde);
result.next(); // go to next line in the customer table
}

Nach Beendigung der Schleife wird der Vektor mit den Datensätzen zurückgegeben.

[ header = Seite 2: Test der Verbindung auf der Standardausgabe ]

Test der Verbindung auf der Standardausgabe

Wir haben nun den JDBC-Treiber, eine Verbindung und eine Methode, die unsere Daten holt. Nun können wir testen, ob dies auch korrekt funktioniert. Wir bauen dazu in unserer Klasse Main, die ebenfalls die Startmethode „main“ beinhaltet, die Datenbankausgabe ein.

Dazu erstellen wir zunächst eine Instanz der Klasse IOManager, auf der wir zunächst die „connectToMySql“-Methode mit den Verbindungsparametern aufrufen.

iom = new IOManager();
if(iom.connectToMysql("vmdb","kunde","root","password") == false)
return;

Danach können wir die Methode „loadCustomers“ mit dem Tabellennamen als Parameter aufrufen. Da die Rückgabe ein Vektor ist, legen wir diesen durch den Variablennamen „kunden“ in den Speicher. Jeder Vektor besitzt die Methode „elements()“, die eine Enumeration liefert. Über diese Enumeration (in unserem Fall wurde sie „e“ genannt) können wir nun an die einzelnen Datensätze gelangen.

Vector kunden = iom.loadCustomers("kunde");
Enumeration e = kunden.elements();
while(e.hasMoreElements())
{
Kunde x = (Kunde) e.nextElement();
System.out.println(x);
}

Sehr praktisch ist vor allen Dingen die Methode „hasMoreElements()“. Wie müssen also nicht einmal mehr ermitteln, wie viel Datensätze vorhanden sind. Dies haben schon andere Programmierer für uns gemacht.

Die gesamte Main-Methode sieht so aus (beachte auch hier wieder, dass ich ein Package verwendete und dies gegebenfalls an Ihre Umgebung angepasst werden müsste):

package javamysql;
import java.util.Enumeration;
import java.util.Vector;
	
public class Main {
IOManager iom;
public static void main(String[] args) {
new Main().start();
}
private void start(){
iom = new IOManager();
if(iom.connectToMysql("vmdb","kunde","root","passwd") == false)
return;
Vector kunden = iom.loadCustomers("kunde");
Enumeration e = kunden.elements();
while(e.hasMoreElements())
{
Kunde x = (Kunde) e.nextElement();
System.out.println(x);
}
}
}

Führen wir nun diesen Code aus, so erhalte ich mit meinen wenigen Testdaten Folgendes:

Abbildung 2

[ header = Seite 3: Datensätze einfügen ]

Datensätze einfügen

Das nächstwichtigste nach einer SQL-Abfrage ist natürlich das Einfügen neuer Datensätze.

Dafür erstellen wir zunächst eine neue Methode in der Klasse IOManager. Der Grund dafür, warum unsere „Einfügemethode“ in der IOManager-Klasse liegt, ist einfach: diese Klasse besitzt die Möglichkeit, mithilfe des connection-Objekts eine Verbindung zur Datenbank aufzubauen.

public boolean saveKunde(String table, Kunde kunde)

In der Methodensignatur erwarten wir zwei Objekte. Ein Objekt vom Typ String, mit dessen Hilfe wir die Tabelle ermitteln. Das zweite Objekt beinhaltet die tatsächlichen Daten, die wir in der Tabelle speichern wollen.

{ Statement stmt = null;

Auch für Einfügeoperationen benötigen wir ein Statement, auf dem wir unseren Query (dieses mal ein Insert-SQl-Befehl) ausführen können. Innerhalb des TRY-Blockes holen wir uns von der Instanzvariablen „connection“ die Verbindungsdetails.

try {
stmt = connection.createStatement();

Das SQL-Statement ist im Hinblick auf den einfachen SELECT-Befehl, etwas komplizierter. Sehen wir uns nochmals kurz die Allgemeine Syntax an:

INSERT INTO tabellenname (datenfeld1,datenfeld2,datenfeld3)
VALUES (wert1,wert2,wert3);

Der obere Ausdruck sagt der Datenbank, dass in die Tabelle „tabellenname“ mit den Feldern „datenfeld“, „datenfeld“, „datenfeld“ ein neuer Datensatz mit den Werten „wert ,wert , wert“ eingefügt werden soll. In der Zeile mit den Werten landet wert1 in der Spalte „datenfeld1“, „wert2“ in der „datenfeld2“-Spalte und „wert3“ in der „datenfeld3“-Spalte.

Umgewandelt in unsere Java-Sprache sieht dies folgendermaßen aus:

String query = "INSERT INTO " + table + " (kid, nachname, vorname) ";
query = query + "VALUES( " + kunde.getKundennummer() + ", "" + kunde.getNachname() + "", "" + kunde.getVorname() + " ")";

Die Variable „table“ erhält von dem Methodenaufruf die Tabellennamen. Die Spalten kid, nachname und vorname sind uns bereits bekannt. In der nächsten Zeile fügen wir dem String nun die Werte hinzu. Dabei rufen wir auf dem übergebenem Kundenobjekt die jeweiligen „getter“-Methoden ab, um diese in den „query“-String einzusetzen. Als Resultat erhalten wir einen vollständigen INSERT-Befehl. Sollten Sie sich zwecks Ihrer SQL-Kenntnisse noch nicht sicher fühlen, so empfehle ich Ihnen dass Sie zunächst den tatsächlichen Query String mit einem println() ausgeben.

stmt.executeUpdate(query);
return true;

Am Ende des TRY/CATCH-Blocks übergeben wir dem Statement mit der Methode executeUpdate() den String und hoffen, dass alles gut geht. Die gesamte Methode, die in der IOManager-Klasse eingefügt wurde, sieht folgendermaßen aus:

public boolean saveKunde(String table, Kunde kunde)
{ Statement stmt = null;
try {
stmt = connection.createStatement();
String query = "INSERT INTO " + table + " (kid, nachname, vorname) ";
query = query + "VALUES( " + kunde.getKundennummer() + ", "" + kunde.getNachname() + "", "" + kunde.getVorname() + " ")";
stmt.executeUpdate(query);
return true;
} catch (Exception ex) {
return false;
}
} 

[ header = Seite 4: Einen neuen Datensatz einfügen ]

Einen neuen Datensatz einfügen

Nun müssen wir die zuvor geschriebene Methode nur noch benutzen. Zu Testzwecken schreiben wir nun Code, der ein Kundenobjekt in die Datenbank einfügt. Dafür verwende ich wieder die Main-Methode. In unserer Methode „saveKunde“ aus der IOManager-Klasse haben wir definiert, dass wir den Tabellennamen (in dem wir etwas einfügen wollen) und das einzufügende Objekt vom Typ Kunde benötigen. Den Tabellennamen bauen wir in unsere „INSERT INTO“-Anweisung ein. Das Kundenobjekt wird mit den GETTER-Methoden ausgelesen und als Wert in die Datenbank gespeichert.

Den IOManager brauchen wir natürlich ebenfalls wieder (ich habe den alten Quellcode komplett entfernt), damit wir eine Verbindung und ein SQL-Statement ausführen können.

Iom = new IOManager();

Das Kundenobjekt mit der Kundennummer 3000, dem Vornamen „Susanne“ und den Nachname „Wolter“.

Kunde neuerKunde = new Kunde(3000, „Susanne“, „Wolter“);

Im nächsten Schritt sollte man die Verbindung mit der Methode connectToMysql aufbauen. Schlägt diese Fehl, so wird mittels „return“ die Methode abgebrochen.

If(iom.connectToMysql(„vmdb“, „kunde“, „root“, „password“) == false){
return;
}

Nun können wir die Methode saveKunde aufrufen. Als Parameter übergeben wir den Tabellennamen sowie das Kundenobjekt neuerKunde:

Iom.saveKunde(„kunden“, neuerKunde);

Dies waren auch schon die ganzen Schritte. Nun befindet sich in unserer Datenbank eine Frau Wolter. Hier der Beweis:

Vector kunden = iom.loadCustomers(„kunden“);
Enumeration e = kunden.elements();
While(e.hasMoreElements()){
Kunde x = (Kunde) e.nextElement();
System.out.println(x);
}

Die Zeilen oberhalb holen alle Datensätze der Tabelle „kunden“ und zeigen Sie auf der Standardausgabe an:

Abbildung 3

Die gesamte Klasse nochmals im Überblick (auch hier wieder der Hinweis: es wurde mit Paketen gearbeitet):

package javamysql;

import java.util.Enumeration;
import java.util.Vector;

public class Main {
IOManager iom;
public static void main(String[] args) {
new Main().start();
}
private void start(){

//der Code, zum Einfügen eines neuen Kunden:
iom = new IOManager();
if(iom.connectToMysql("vm", "kunde", "root", "passwd") == false){
return;
}
	
Kunde neuerKunde = new Kunde(3000, "Susanne", "Wolter");

iom.saveKunde("kunden", neuerKunde);
	
	
//Hier werden Daten abgefragt und auf der Standardausgabe ausgegeben
Vector kunden = iom.loadCustomers("kunden");
Enumeration e = kunden.elements();
while(e.hasMoreElements()){
Kunde x = (Kunde) e.nextElement();
System.out.println(x);
}

}

}
Christian Barthel macht eine Ausbildung zum Informatikkaufmann. Neben den Themen der Programmierung mit Java beschäftigt er sich ebenfalls mit Linux, Perl und infrastrukturellen Themen wie z. B. Backup, Dokumentmanagement mit Alfresco und Virtualisierung mit KVM, Xen und VMware. Durch seine Offenheit steht er sehr gerne mit anderen Menschen in Kontakt und tauscht Wissen über seine Interessensgebiete aus: christian.barthel@hotmail.de
Geschrieben von
Christian Barthel
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.