Wie lässt sich in Java eine eingebettete Datenbank realisieren?
Die gesamte Routine wird von einem try-catch-Block umschlossen,
um SQL-Exceptions abzufangen.
Als erstes muss der Treiber
geladen werden:
Class.forName("org.h2.Driver");
Hierzu ist es notwendig, die jeweils aktuelle Jar-Datei unter http://www.h2database.com/html/download.html
herunterzuladen und in den Classpath einzubinden. Vergessen Sie
auch nicht, bei Verwendung von Eclipse die Datei in den
Build-Path aufzunehmen. (Project-Properties → Java Build
Path).
Der nächste Schritt besteht darin, eine
Verbindung zur Datenbank aufzubauen. Dies geschieht durch die
statische Methode DriverManager.getConnection(). Sie
erwartet drei Parameter
- den URL zur Datenbankdatei
- den Nutzernamen
- das Zugangs-Passwort
Der Datenbank-URL muss in der Form jdbc:h2:<PfadZurDatei>
angegeben werden, wobei der Pfad relativ oder absolut angegeben
werden kann. Ist keine Datenbank-Datei angelegt, so wird sie
gebildet. Im Beispiel befindet sie sich im versteckten
Verzeichnis <UserHome>/.javabeginners und
trägt den Namen h2Test.h2.db. Die Dateiendung h2.db
darf nicht mit angegeben werden. Wird kein Pfad angegeben, so
wird das aktuelle Arbeitsverzeichnis als Speicherort verwendet.
Nutzername und Passwort sind optional und können leer
bleiben, bzw. selbstverständlich wie auch der Datenbankname
über eine Benutzeroberfläche dynamisch zur Laufzeit
eingegeben werden. Auf diese Weise könnten z.B.
individuelle Programm-Einstellungen gespeichert werden.
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class H2Class {
public static void main(String[] a) throws Exception {
Class.forName("org.h2.Driver");
readDB();
}
public static void readDB() {
String tab = "TESTTABELLE";
try (Connection conn = DriverManager.getConnection("jdbc:h2:~/.javabeginners/h2Test", "", "")) {
DatabaseMetaData md = conn.getMetaData();
String[] types = { "TABLE", "SYSTEM TABLE" };
ResultSet metaRS = md.getTables(null, null, "%", null);
while (metaRS.next()) {
String tableCatalog = metaRS.getString(1);
System.out.println("Catalog: " + tableCatalog);
String tableSchema = metaRS.getString(2);
System.out.println("Tabellen-Schema: " + tableSchema);
String tableName = metaRS.getString(3);
System.out.println("Tabellen-Name: " + tableName);
String tableType = metaRS.getString(4);
System.out.println("Tabellen-Typ: " + tableType + "\n");
}
Statement stmt = conn.createStatement();
String dropQ = "DROP TABLE IF EXISTS " + tab;
stmt.executeUpdate(dropQ);
String createQ = "CREATE TABLE IF NOT EXISTS " + tab
+ "(ID INT PRIMARY KEY AUTO_INCREMENT(1,1) NOT NULL, NAME VARCHAR(255))";
stmt.executeUpdate(createQ);
String insertQ = "INSERT INTO " + tab + " VALUES(TRANSACTION_ID(),'Hello World!')";
stmt.executeUpdate(insertQ);
ResultSet selectRS = stmt.executeQuery("SELECT * FROM " + tab);
while (selectRS.next()) {
System.out.printf("%s, %s\n", selectRS.getString(1), selectRS.getString(2));
}
System.out.println("Liste Tabellen...");
String tablesQ = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='PUBLIC'";
ResultSet tablesRS = stmt.executeQuery(tablesQ);
while (tablesRS.next()) {
System.out.printf("Tabelle %s vorhanden \n", tablesRS.getString(1));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Tabellen-Metadaten auslesen
Über das Connection-Objekt werden mit Hilfe der Methode getMetaData()
die Meta-Daten der Datenbank abgerufen. Sie müssen nun nach
den gewünschten Typen gefiltert werden. Dies geschieht
durch die Übergabe eines String-Arrays, in das diese
eingetragen werden, an die Methode getTables() des
DatabaseMetaData-Objektes. Im Beispiel werden die Metadaten der
System-Tabellen und der vom Nutzer angelegten Tabellen
abgefragt. Möchte man nur die Ausgaben für die
Nutzertabellen abfragen, so entfernt man den Eintrag SYSTEM
TABLE aus dem Array.
Neben
den genannten können hier auch die folgenden Typen
gewählt werden:
- "VIEW"
- "GLOBAL TEMPORARY"
- "LOCAL TEMPORARY"
- "ALIAS"
- "SYNONYM"
Die anderen drei Parameter, catalog, schemaPattern
und tableNamePattern, können verwendet werden, um
die Suche weiter einzuschränken. Die Angabe null
für die ersten beiden Parameter bewirkt, dass diese
Einschränkungen nicht verwendet werden. Das Prozentzeichen
% des dritten Parameters bewirkt das Auslesen aller
eingetragenen Tabellen.
In der Folge wird über das ResultSet
iteriert, um die Einträge auszugeben.
Abfragen und Updates
Das Interface java.sql.Statement liefert ein Objekt zum Absetzen von Datenbank-Anfragen und zur Ausgabe der entsprechenden Ergebnisse. Im Beispiel werden auf ihm zwei verschiedene Methoden aufgerufen:
- executeUpdate() liefert einen int-Wert und wird für INSERT-, UPDATE- und DELETE-Statements verwendet. Der Statement-String wird als Parameter übergeben.
- executeQuery() liefert ein ResultSet und wird üblicherweise für SELECT-Abfragen eingesetzt.
Die Tabelle mit dem in der Variablen tab gespeicherten Namen wird im Folgenden der Reihe nach
- gelöscht, falls sie bereits existiert
- neu erzeugt, falls sie noch nicht existieren sollte
Hier fällt die SQL-Funktion AUTO_INCREMENT(1,1) auf. Die Parameter geben an, dass die automatische Incrementierung des ID-Wertes bei 1 beginnen und in Einer-Schritten erfolgen soll. - mit einem neuen Eintrag versehen
Hier ist zu beachten, dass der Auto-Increment-Wert der ID nicht, wie etwa bei MySQL, selbstständig erzeugt und incrementiert wird, sondern, dass hierfür die Funktion TRANSACTION_ID() eingetragen werden muss. - ausgelesen
Den Abschluss bildet eine weitere Form der Ermittlung der existierenden User-Tabellen: Auch hier stellt eine SELECT-Abfrage die Grundlage dar, um ein ResultSet zu erhalten, das durchlaufen und ausgegeben werden kann. Mit conn.close() wird die Verbindung zur Datenbank schließlich geschlossen.