Verknüpfung mit Java

Die Abiturklassen

Einführung

Wir lernen nun, wie wir von Java aus auf eine Datenbank zugreifen können. Dabei verwenden wir die beiden Abiturklassen QueryResult und DatabaseConnector. Ihre offiziellen Dokumentationen sowie die Klassen selbst sind hier zu finden.

Betrachten wir ein Diagramm, das die beiden Klassen beschreibt:

Klassendiagramm der beiden relevanten Abiturklassen
Klassendiagramm der beiden relevanten Abiturklassen

Die Klasse QueryResult modelliert das Ergebnis einer SQL-Abfrage in Form eines zweidimensionalen String Arrays – also letztlich also Tabelle. Gehen wir kurz auf ihre Methoden ein – das folgende Beispiel wird danach sicherlich noch für mehr Klarheit sorgen:

String [][] getData() Diese Methode liefert das zweidimensionale String-Array zurück, das das Ergebnis der letzten SQL-Abfrage darstellt. Der erste Index gibt dabei die Zeile und der zweite Index die Spalte an.
String[] getColumnNames() Hiermit erhalten wir die Überschriften der Spalten unserer Ergebnistabelle wie sie in der gegebenen Datenbank verwendet werden.
String[] getColumnTypes() Dies liefert uns die Datentypen der Spalten. Die Datentypen werden dabei einfach als Strings (also als Text) angegeben. Die Bezeichnungen richten sich nach der Datenbank.
int getRowCount() Liefert die Anzahl der Zeilen der Ergebnistabelle.
int getColumnCount() Liefert die Anzahl der Spalten der Ergebnistabelle.

Es fällt vielleicht auf, dass diese Klasse keinen öffentlichen Konstruktor besitzt. Das ist sinnvoll, denn schließlich wollen wir die Ergebnistabellen nicht selbst erstellen. Dies erledigt für uns ein Objekt der Klasse DatabaseConnector.

Hier eine Übersicht über ihre Methoden:

DatabaseConnector(String pIP, int pPort, String pDatabase, String pUsername, String pPassword) Ein neues Objekt dieser Klasse wird erstellt und baut eine Verbindung zur angegeben Datenbank auf. Arbeiten wir mit SQLite ist einzig der Parameter pDatabase relevant.
void executeStatement(String pSQLStatement) Die SQL-Anweisung pSQLStatement wird ausgeführt.
QueryResult getCurrentQueryResult() Liefert das Ergebnis der zuletzt ausgeführten SQL-Anweisung. Handelte es sich um einen INSERT- oder DELETE-Befehl, wird hier null geliefert.
String getErrorMessage() Falls es bei der letzten Ausführung eines Anweisung einen Fehler gab, wird dieser als String geliefert. Gab es keinen, so erhalten wir null.
void close() Schließt die Verbindung zur Datenbank.

Beispiel für einen Probedurchlauf

Wir wenden die beiden Abiturklassen nun in einem einfachen Beispiel an.

Dafür verwenden wir die Datenbank Schuelerdaten.db, die hier als zip-Datei heruntergeladen werden kann. Bei den Daten handelt es sich um zufällig erzeugte Kombinationen von Namen, Vornamen etc..
Nach dem Runterladen muss sie entpackt und in den Projektordner verschoben werden, in dem sich das Java-Projekt befindet, von wo aus wir auf die Daten zugreifen wollen.
Wenn beim Testen etwas schiefgeht, liegt es übrigens sehr häufig daran, dass sich die Datei an einer falschen Stelle befindet!

In unserem Projekt benötigen wir außerdem die beiden oben beschriebenen Abiturklassen und die Abiturklasse Queue.

Haben wir alles vorbereitet, können wir dieses Beispiel erstellen:

import databases.DatabaseConnector;

public class Testlauf {
 public static void main(String[] args) {
  /* Ein Objekt der Klasse DatabaseConnector wird erstellt.
  SQLite verlangt als einzige Angabe den Namen der Datei!
  Die anderen Angaben sind irrelevant.
  */  
  DatabaseConnector meinConnector = new DatabaseConnector("", 0, "Schuelerdaten.db", "", "");
  
  /*
  Eine SQL-Anweisung wird ausgeführt.
  */
  meinConnector.executeStatement("select * from Schueler");
  /*
  Zur Sicherheit sollten wir sehr häufig die Fehlermeldungen prüfen.
  */
  System.out.println(meinConnector.getErrorMessage());
  
  /*
  Das Ergebnis wird in der Konsole angezeigt.
  */
  for (int i=0; i<meinConnector.getCurrentQueryResult().getRowCount(); i=i+1) {
   
   for (int j=0; j<meinConnector.getCurrentQueryResult().getColumnCount(); j=j+1) {
    System.out.print(meinConnector.getCurrentQueryResult().getData()[i][j]+" ");
   }
   
   System.out.println();
  }

 }

}

Hat alles funktioniert, werden die Daten der gespeicherten Schüler ausgegeben.

Sehen wir uns noch eine Modifizierung des Beispiels an:

import java.util.Scanner;

public class Testlauf {

 public static void main(String[] args) {

  DatabaseConnector meinConnector = new DatabaseConnector("", 0, "Schuelerdaten.db", "", "");

  Scanner meinScanner = new Scanner(System.in);

  System.out.println("Welcher Nachname ist gesucht?");
  String nachname = meinScanner.next();

  meinConnector.executeStatement("select * from Schueler where name = '" + nachname + "'");

  if (meinConnector.getCurrentQueryResult().getRowCount() == 0) {
   System.out.println("Der Name ist nicht vorhanden!");
  } else {
   for (int i = 0; i < meinConnector.getCurrentQueryResult().getRowCount(); i = i + 1) {

    for (int j = 0; j < meinConnector.getCurrentQueryResult().getColumnCount(); j = j + 1) {
     System.out.print(meinConnector.getCurrentQueryResult().getData()[i][j] + " ");
    }

    System.out.println();
   }
  }
  meinScanner.close();
 }
}

Hier wird man beim Start nach einem Nachnamen gefragt. Dieser wird dann eingelesen und passende Schüler werden gesucht. Gibt keinen Schüler mit dem gesuchten Nachnamen, erscheint eine entsprechende Meldung.
Dass es keinen passenden Datensatz gibt, kann man, wie man hier sieht, sehr schön mit der Bedingung  meinConnector.getCurrentQueryResult().getRowCount() == 0überprüfen, denn diese sagt aus, dass keine passenden Zeilen gefunden wurden, d.h., dass die Ergebnistabelle keine Zeilen enthält.

Beispielanwendung

Hier möchte ich an das (kleine) Trainingsprojekt Kiosk zur Einführung von Queues anknüpfen. Es empfiehlt sich, dieses vor dem Weiterlesen anzusehen!

Die folgende Klasse ist eine Unterklasse von Kiosk, die an einem einfachen Beispiel zeigen soll, wie die Abiturklassen zur Verknüpfung mit einer Datenbank eine Anwendung finden könnten:

public class DatenbankKiosk extends Kiosk {

 DatabaseConnector meinConnector;

 public DatenbankKiosk(String pDatenbank) {
  super();
  meinConnector = new DatabaseConnector("", 0, pDatenbank, "", "");
 }

 public boolean istInDatenbank(int pId) {
  meinConnector.executeStatement("select * from Schueler where SID=" + pId);

  return (meinConnector.getCurrentQueryResult().getRowCount() > 0);
 }

 public Schueler gibSchueler(int pId) {
  meinConnector.executeStatement("select Vorname, Name, Bezeichnung from Schueler where SID=" + pId);

  if (meinConnector.getCurrentQueryResult().getRowCount() > 0) {
   Schueler ergebnis;

   if (meinConnector.getCurrentQueryResult().getData()[0][2].equals("Q2")
     || meinConnector.getCurrentQueryResult().getData()[0][2].equals("Q1")
     || meinConnector.getCurrentQueryResult().getData()[0][2].equals("EF")) {
    // Oberstufenschüler anstellen:
    ergebnis = new Schueler(meinConnector.getCurrentQueryResult().getData()[0][0]
      + " " + meinConnector.getCurrentQueryResult().getData()[0][1], true);
   } else {
    // Unter- / Mitteltufenschüler anstellen:
    ergebnis = new Schueler(meinConnector.getCurrentQueryResult().getData()[0][0]
      + " " + meinConnector.getCurrentQueryResult().getData()[0][1], false);
   }

   return ergebnis;
  } else {
   return null;
  }
 }

 public void stelleAn(int pId) {
  Schueler neuer = gibSchueler(pId);

  if (neuer != null) {
   super.stelleAn(neuer);
  }
 }
}