HSQLDB als lokale Datenbank
Die HyperSQL Datenbank
HSQLDB ist vollständig in Java geschrieben. Die gesamte
Funktionalität ist im Archiv hsqldb.jar
gekapselt. Die Datei befindet sich in einem ZIP-Archiv, das
unter https://sourceforge.net/projects/hsqldb/files/
herumtergeladen werden muss und je nach Verwendung
bereitgestellt wird1. Das ZIP-Archiv enthält zusätzlich
eine ausführliche englischsprachige Dokumentation.
Soll die Datenbank innerhalb einer Java-Standalone-Application
genutzt werden, so bietet sich hierzu die
Integration in den Classpath an.
Das Archiv
enthält drei Elemente:
- das relationale Datenbankmanagementsystem als Kern
- den HyperSQL JDBC Driver, der bei der Nutzung der Datenbank durch ein Programm geladen werden muss, um die Verbindung zur Datenbank herzustellen
- einen Database Manager, als GUI-basiertes Datenbank-Verwaltungs-Werkzeug, jeweils in einer Swing- und einer AWT-Version.
Um das Manager-Tool aufzurufen, wechselt man auf der Konsole in
das Verzeichnis, in dem hsqldb.jar
gespeichert ist
und tätigt dann, je nach gewünschtem GUI, einen der
beiden folgenden Aufrufe:
java -cp hsqldb.jar org.hsqldb.util.DatabaseManager // AWT java -cp hsqldb.jar org.hsqldb.util.DatabaseManagerSwing // Swing
Die Datenbank selber muss nicht gesondert erzeugt werden. Sie wird, falls sie noch nicht existiert, automatisch gebildet, wenn ein Nutzer durch Aufruf der geeigneten URL die Verbindung herstellt. Die hierzu notwendige URL besitzt die folgende Form
jdbc:hsqldb:<datenbank>
<datenbank> muss hierbei durch eine Angabe ersetzt werden,
die je nach Typ der gewünschten Datenbank variiert.
Um
die Verbindung herzustellen, wird als Standard der Nutzer SA
mit einem leeren Passwort verwendet. Hier kann ein beliebiges
Passort, auch ein leeres, eingesetzt werden.
Selbstverständlich jedoch müssen beim
anschließenden Verbinden mit der dann existierenden
Datenbank diese Angaben wieder verwendet werden.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class HSQLDB {
public static void main(String[] args) {
runMem();
}
private static void runMem() {
System.out.println("Database in Memory:");
ResultSet rs = null;
Statement stmt = null;
Connection c = null;
try {
c = DriverManager.getConnection(
"jdbc:hsqldb:mem:mymemdb;shutdown=true", "jb", "123");
String query = "CREATE TABLE IF NOT EXISTS PUBLIC.USERS (name CHAR(25), age INTEGER NOT NULL);";
stmt = c.createStatement();
stmt.executeQuery(query);
query = "INSERT INTO USERS (name, age) VALUES ('Donald Duck', 83)";
rs = stmt.executeQuery(query);
rs.close();
query = "SELECT * FROM USERS;";
rs = stmt.executeQuery(query);
while (rs.next()) {
System.out.println(rs.getString("name"));
System.out.println(rs.getInt("age"));
}
rs.close();
stmt.close();
c.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (rs != null && !rs.isClosed())
rs.close();
if (stmt != null && !stmt.isClosed())
stmt.close();
if (c != null && !c.isClosed())
c.close();
} catch (SQLException e) {
}
}
}
}
Datenbank im Speicher
Im einfachsten Fall wird eine Datenbank, HSQLDB spricht von einem Catalog, direkt im Speicher angelegt. Auf diese Weise wird sie jedes Mal neu erzeugt, ist unabhängig von speichernden Dateien und kann so gut zu Testzwecken oder zum Speichern von temporären Programmdaten verwendet werden.
Das o.a. Beispiel stellt ein lauffähiges Programm dar, das
eine Datenbank im Speicher erzeugt, eine Tabelle USERS
mit zwei Spalten name
und age
anlegt
und dort anschließend einen Nutzer Donald Duck mit
dem Alter 83 einträgt. Anschließend wird der
Eintrag wieder ausgelesen und ausgegeben.
Die gesamte Routine
befindet sich in der Methode runMem()
, die in main()
auf einem Objekt der Klasse aufgerufen wird.
Innerhalb eines try-catch
-Blockes, der dem Abfangen
von SQL-Fehlern dient, wird als erstes eine Verbindung zur
Datenbank erzeugt.
DriverManager.getConnection("jdbc:hsqldb:mem:mymemdb;shutdown=true", "jb", "123");
Wie oben erläutert, wird hierbei die Datenbank automatisch
neu erzeugt. Der Methode getConnection()
werden
drei Parameter übergeben. Die letzten beiden sind der
Benutzername jb
und das Passwort 123
.
Der erste Parameter stellt die URL zur Datenbank dar. Hierbei
erzeugt der Ausdruck mem:mymemdb
eine Datenbank mit
Namen mymemdb
im Speicher. Der durch Semikolon
abgegrenzte String shutdown=true
stellt eine
Verbindungseigenschaft dar und sorgt dafür, dass die
Datenbank nach dem Schließen der letzten Verbindung
ebenfalls geschlossen wird.
Der dann folgende Quelltext
entspricht der in Java gängigen Datenbank-Handhabung, bei
der Querys erzeugt, diese durch ein Statement
ausgeführt und die Ergebnisse schließlich ggf. in
einem ResultSet
gespeichert und ausgegeben werden.
Datenbank in Datei
Möchte man die Datenbank statt im Speicher persistent in einer Datei erzeugen, reicht prinzipiell der Austausch der Zeile, in der die Verbindung hergestellt wird.
String fileName = "testdb"; DriverManager.getConnection("jdbc:hsqldb:file:" + fileName, "jb", "123");
Im Vergleich zum vorhergehenden Beispiel erkennt man, dass
lediglich der Ausdruck mem:mymemdb
gegen file:testdb
getauscht wurde. Es liegt auf der Hand, dass hier angegeben
wird, dass eine Datenbank mit Namen testdb
in einer
Datei im Arbeitsverzeichnis zu erzeugen ist. Eine Pfadangabe
kann an dieser Stelle übrigens sowohl absolut, als auch
relativ erfolgen.
Führt man die Datei mit dieser Verbindungsangabe aus, so stellt man fest, dass unter dem angegebenen Pfad ein Verzeichnis und drei Dateien neu erzeugt werden.
-
testdb.tmp
- Ein temporäres Verzeichnis, das darauf hinweist, dass die Datenbank nicht korrekt geschlossen wurde.
-
testdb.log
- Eine Text-Datei, die die kürzlich vorgenommenen Datenänderungen enthält.
-
testdb.properties
- Eine Text-Datei, die Angaben zu den Datenbank-Eigenschaften enthält.
-
testdb.script
- Eine Text-Datei, die die Tabellen-Definitionen und die Daten enthält.
Das Vorhandensein des *.tmp
-Verzeichnisses und der
*.log
-Datei weist darauf hin, dass die Datenbank
nach der Ausführung des Programms nicht vollständig
geschlossen wurde. Dies lässt sich verhindern, indem die
Eigenschafts-Angabe shutdown=true
an den
Datenbankpfad durch Semikolon getrennt angehängt wird.
DriverManager.getConnection("jdbc:hsqldb:file:" + fileName + ";shutdown=true", "jb", "123");
Führt man das Programm in dieser Form zwei Mal hintereinander aus, so erhält man die folgende Ausgabe:
Database in File: Donald Duck 83 Donald Duck 83
Ein Blick in testdb.script
zeigt am Ende den
Eintrag
//... SET SCHEMA PUBLIC INSERT INTO USERS VALUES(1,'Donald Duck ',83) INSERT INTO USERS VALUES(1,'Donald Duck ',83)
Man erkennt hier, dass die bisherigen Einträge in Form der SQL-Querys gespeichert werden. Sie stellen den eigentlichen Datenspeicher dar. Aus anderen DBMS bekannte Binärdateien sucht man bei diesem System vergebens.
Datenbank als *.csv-Datei
HSQLDB erlaubt auch die Verwendung einer *.csv
-Datei
als Datenbankspeicher. Bei Nichtexistenz wird sie neu erstellt.
Es können aber auch bereits bestehende Dateien verwendet
werden, sofern die Datenstruktur der geforderten
Tabellenstruktur entspricht.
Die Verbindung wird auf die
gleiche Weise hergestellt, wie beim obigen Beispiel, allerdings
muss zusätzlich die *.csv
-Datei als Quelle des
Tabelleninhaltes eingetragen werden.
DriverManager.getConnection("jdbc:hsqldb:file:" + fileName + ";shutdown=true", "jb", "123"); //... query = "SET TABLE USERS SOURCE 'test.csv;fs=\\semi'"; stmt.executeQuery(query);
Die Eigenschaft fs=\\semi
sorgt dafür, dass in
diesem Fall das Semikolon als Feldtrenner verwendet wird.
Weitere Trenner können unter der Überschrift Configuration
im Kapitel
5, Text Tables, in der HSQLDB-Dokumentation
nachgeschlagen werden. Bitte beachten: Die dort angegebenen
Backslashes '\' müssen wie im Beispiel ihrerseits
jeweils durch einen Backslash maskiert werden.
Datenbank auf Server
Meist wird eine HSQL-Datenbank wohl lokal betrieben werden. Sie kann jedoch auch auf einem Server eingerichtet und so über ein Netzwerk bereitgestellt werden. Hierzu muss die Datenbank mit Hilfe des folgenden Befehls zunächst auf dem Server erzeugt und gestartet werden:
java -cp <pfad>/hsqldb.jar org.hsqldb.server.Server --database.0 file:mydb --dbname.0 dbtest
Die Angabe <pfad>
bezeichnet hierbei den
relativen oder absoluten Pfad zum Verzeichnis, in dem hsqldb.jar
abgelegt ist. Die Konfigurationsdateien der erzeugten Datenbank
mit den Bezeichnern mydb.*
werden dann in dem
Verzeichnis erstellt, von dem aus der Kommandozeilenbefehl
abgesetzt wurde. Der am Ende angegebene Name dbtest
wird im Client zur Ansprache der DB verwendet und verschleiert
so den Datenbanknamen mydb
.
Sollen zwei
Datenbanken erzeugt werden, müssen die Angaben zu den
letzten beiden Parametern verdoppelt werden:
java -cp <pfad>/hsqldb.jar org.hsqldb.server.Server --database.0 file:mydb --database.1 file:yourdb --dbname.0 mdb --dbname.1 ydb
Eine Übersicht über die verwendbaren Parameter findet sich nach Eingabe von
java -cp <pfad>/hsqldb.jar org.hsqldb.server.Server --help
Nach dem Start der Datenbank wird neben den oben bereits
angesprochenen Dateien für jede Datenbank noch eine *.lck
-Datei
angelegt, die die laufende Datenbank sperrt. Beenden lässt
sie sich auf der Konsole hart durch Ctrl + C
oder,
besser, durch ein SQL-Statement SHUTDOWN
.
Die Verbindung zur Datenbank erfolgt idealerweise durch ein
proprietäres hsql
-Protokoll, kann jedoch auch
per http
erfolgen, wenn der Zugriff zwingend per http
erfolgen muss. Hierzu muss dann statt org.hsqldb.server.Server
im obigen Befehl die Klasse org.hsqldb.server.WebServer
aufgerufen werden. Zudem sollte der Start als root
erfolgen und möglichst einen eigenen Port < 1023
verwenden.
sudo java -cp <pfad>/hsqldb.jar org.hsqldb.server.WebServer --database.0 file:mydb --dbname.0 mdb --port 999
1) Verwendete Version: 2.7.1 | Es muss beachtet werden, dass bei Einbindung einer anderen Version, der vorliegende Quelltext möglicherweise nicht mehr fehlerfrei lauffähig ist!
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.