Wem kommt das folgende Szenario nicht bekannt vor? Man kommt in ein neues Projekt, möchte sich einen Überblick über das Datenbankmodell verschaffen, und muss feststellen, dass die Dokumentationsseite in Confluence (sofern sie überhaupt existiert) bereits seit einem halben Jahr oder länger nicht mehr aktualisiert wurde. Dabei gibt es DB-Skripts mit Schemaänderungen, die sehr viel jüngeren Datums sind.
Dokumentation: das notwendige Übel
Obwohl Dokumentation oft als lästige Pflicht wahrgenommen wird, ist sie angesichts ihrer zentralen Bedeutung keinesfalls zu vernachlässigen. Um die Dokumentation einer kontinuierlich weiterentwickelnden Software stets aktuell zu halten, bedarf es klar definierter Maßnahmen. So sollte der Softwareentwicklungsprozess beispielsweise Vorgaben enthalten – etwa, dass die Aktualisierung der Dokumentation als fester Bestandteil der Definition of Done gilt, wenn im Rahmen einer Story Änderungen am DB-Schema vorgenommen werden. Hinzu kommt die notwendige Disziplin, diese Vorgaben konsequent einzuhalten.
In DB veritas
Abweichungen zwischen Dokumentation und tatsächlich implementiertem Schema sind trotz allem schwer zu vermeiden. Letztendlich steckt die Wahrheit also oft nur in der Datenbank selbst.
Wieso also nicht das Pferd von hinten aufzäumen, und die Dokumentation per Reverse Engineering aus der DB generieren lassen? Wenn die Dokumentation ohnehin lediglich aus ERM-Diagrammen, einer kurzen Beschreibung pro Tabelle sowie einer Auflistung der Spaltennamen und zugehörigen Datentypen besteht, ist dies recht einfach zu bewerkstelligen.
Für diesen Zweck gibt es verschiedene Werkzeuge. Eines davon ist SchemaSpy. Es ist ganz einfach zu verwenden. Lizenziert ist es unter der LGPL, das heißt, es darf also auch für kommerzielle Zwecke genutzt werden.
Vorbereitung der Demo-Datenbank
Zunächst benötigen wir eine Datenbank. SchemaSpy unterstützt viele verschiedene Datenbanksysteme, wie z.B. PostgreSQL, Oracle, MySQL, H2DB oder Microsoft SQL Server, um nur ein paar zu nennen. Für diese Demo starten wir eine PostgreSQL-DB in einem Dockercontainer:
docker run --name postgres-db-doku-demo -p 5432:5432 -e POSTGRES_PASSWORD=password -d postgres:latest
Zur Anmeldung an die Datenbank benötigen wir die folgenden Konfigurationsdaten:
- Datenbank: postgres
- Benutzer: postgres
- Passwort: password
- Host: localhost
- Port: 5432
Nun brauchen wir noch ein entsprechendes DB-Schema, für das die Dokumentation erstellt werden soll. In dieser Demo verwende ich das Schema aus dem Spring-Beispielprojekt „Pet Clinic“1. Ein SQL-Skript zum Anlegen der Tabellen habe ich unter dem folgenden Link als GitHub Gist hinterlegt:
Nach Ausführung des Skripts im Datenbankclient der Wahl des geneigten Lesers steht der Generierung der Datenbankbeschreibung mit SchemaSpy nichts mehr im Wege.
Datenbank-Doku erstellen mit SchemaSpy
Wer das Beispiel nicht selbst durchexerzieren möchte, kann sich das Ergebnis direkt hier online anschauen: https://dsblog-db-doku.fly.dev/index.html
Für die Arbeit mit SchemaSpy benötigen wir die folgenden Artefakte:
- Eine aktuelle Java-Runtime, da SchemaSpy ein Java-Programm ist
- SchemaSpy selbst. Hierzu laden wir uns die Jar-Datei des aktuellen Releases von Github herunter (https://github.com/schemaspy/schemaspy/releases). Zur Zeit der Veröffentlichung dieses Blogbeitrags war das schemaspy-6.2.4.jar. Die Datei speichern wir ohne Versionsnummer im Namen ab, also schemaspy.jar.
- Einen Datenbanktreiber, den SchemaSpy für die Verbindung zur Datenbank benötigt. Dieser ist abhängig von der verwendeten Datenbank. In unserem Fall ist dies der PostgreSQL JDBC Driver, ebenfalls erhältlich auf GitHub: https://github.com/pgjdbc/pgjdbc/releases. Auch hier laden wir uns die entsprechende Jar-Datei herunter (in diesem Beispiel postgresql-42.7.5.jar) und lassen die Versionsnummer im Dateinamen weg (postgresql.jar)
Die von SchemaSpy benötigten Konfigurationsinformationen legen wir in der Datei schemaspy.properties ab, in demselben Verzeichnis, in dem auch die beiden Jar-Dateien liegen:
# type of the database. Run with -dbhelp for details schemaspy.t=pgsql11 # path to JDBC driver schemaspy.dp=./postgresql.jar # database properties: host, port number, name user, password schemaspy.host=localhost schemaspy.port=5432 schemaspy.db=postgres schemaspy.u=postgres schemaspy.p=password # output dir to save generated files schemaspy.o=./output # DB scheme for which to generate the docs schemaspy.s=petclinic
In diesem Verzeichnis führen wir SchemaSpy nun aus:
java -jar schemaspy.jar -vizjs
Der Parameter -vizjs weist SchemaSpy an, das im Jar enthaltene viz.js zu verwenden. Ohne diesen Parameter versucht SchemaSpy, Graphviz zu verwenden, das auf dem Rechner vorinstalliert sein muss. Graphviz bzw. viz.js werden für die Generierung der ERM-Diagramme benötigt.
Wenn alles funktioniert hat, liegt die generierte Dokumentation nun im von SchemaSpy erzeugten Unterordner namens output. Um die Doku anzuschauen öffnet man die darin enthaltene Datei index.html in einem Webbrowser.
Die generierte Doku
Die Startseite gibt gleich einen Überblick über die im Schema enthaltenen Datenbankobjekte.

Von hier aus kann man zu den Detailansichten der Tabellen, Views etc. navigieren.
Über die Reiter ganz oben kann man interessante Einblicke über das Schema gewinnen:
- Tables: Übersicht über alle Tabellen und Views
- Columns: Die Spalten aller Tabellen und Views in einer großen Tabelle
- Constraints: Datenbank-Constraints wie z.B. Foreign Keys
- Relationships: Ein Diagramm, in dem alle Tabellen mit Foreign-Key-Beziehungen dargestellt werden (in kompakter oder ausführlicher Darstellung; die ausführliche Darstellung zeigt alle Spalten an, die kompakte nur Primär- sowie Fremdschlüssel und Indizes)
- Orphan Tables: Tabellen ohne relationale Beziehungen
- Anomalies: Punkte, die ggf. auf ein mangelhaftes Datenbankdesign hindeuten könnten, wie z.B. Tabellen mit nur einer Spalte, Tabellen ohne Inidizes, o.ä.
- Routines: Funktionen und Prozeduren
Die Tabellen-, View- und Spaltenbeschreibungen können übrigens per Knopfdruck bequem nach Excel, CSV oder PDF exportiert sowie in die Zwischenablage kopiert werden.

Sag‘s mit Kommentaren
Viele Datenbanksysteme bieten die Möglichkeit, Datenbankobjekte wie Tabellen, Views oder Spalten mit Kommentaren zu versehen mit der Syntax
COMMENT ON <db object> IS ‘some comment’
Konkrete Beispiele (diese finden sich auch im oben erwähnten Schemaerstellungsskript create_pet_db_schema.sql):
-- describe table pets in schema petclinic
COMMENT ON TABLE petclinic.pets IS 'Stores pet information, linking each pet to its owner and pet type.';
-- describe column id of table pets
COMMENT ON COLUMN petclinic.pets.id IS 'Unique identifier for each pet, auto-generated via a sequence.';
Diese Kommentare werden von SchemaSpy ausgelesen und in der jeweiligen „Comments“-Spalte angezeigt:

Da wie schon gesagt die ganze Wahrheit in der Datenbank steckt, sollten auch die Tabellen- und Spaltenbeschreibungen dort verortet sein. Dafür eignen sich die Kommentare sehr gut.
Einmal automatisieren, bitte!
Nun könnte man jedes Mal, wenn sich das Datenbankschema ändert, die Dokumentation von Hand erstellen. Besser ist jedoch, wenn dieser Prozess automatisiert wird.
Wenn ein Datenbank-Versionierungstool wie Flyway oder Liquibase verwendet wird (was sowieso immer eine gute Idee ist), koppelt man die Generierung der DB-Dokumentation idealerweise an den Prozess, der die Schemaänderungen an der Datenbank ausrollt. Hat man beispielsweise eine Build-Pipeline, mit derer die Flyway- bzw. Liquibase-Skripte ausgeführt werden, kann diese nach erfolgreicher Ausführung den Dokumentationserzeugungsprozess anstoßen.
Als Basis kann dieses Dockerfile dienen, das die Dokumentation generiert und zur Auslieferung in einen Container mit einem nginx-Webserver packt:
# STAGE 1: create DB documentation with SchemaSpy FROM amazoncorretto:21 as schemaspy-builder # set the working directory WORKDIR /schemaspy # copy schema spy and JDBC driver COPY schemaspy.jar . COPY postgresql.jar . # copy the SchemaSpy configuration file COPY schemaspy.properties . # execute SchemaSpy RUN java -jar schemaspy.jar -vizjs --host host.docker.internal -dp postgresql.jar -o /output # STAGE 2: Nginx container for serving the documentation FROM nginx:latest # copy the documentation COPY --from=schemaspy-builder /output /usr/share/nginx/html # Expose port 80 for the webserver EXPOSE 80 # Start Nginx CMD ["nginx", "-g", "daemon off;"]
Das Image wird mit dem folgenden Befehl gebaut:
docker build -t db-doku .
Damit dies funktioniert, muss sichergestellt sein, dass die Datenbank aus dem Docker-Container heraus erreichbar ist. Alternativ kann die Dokumentation auch außerhalb von Docker gebaut, und erst danach in das nginx-Image kopiert werden.
Die Datenbankverbindungsdaten können der Pipeline entweder über die schemaspy.properties-Datei, oder besser, als Umgebungsvariablen übergeben werden.
Fazit
Um die Datenbankdokumentation stets aktuell zu halten, und sich die manuelle Erstellung derselben zu ersparen, automatisiert man diesen Prozess am besten.
SchemaSpy erzeugt eine umfangreiche HTML-Dokumentation mit Exportfunktionalität nach Excel, CSV und PDF.
Kommentare auf Datenbankobjekte dienen als Beschreibung, und werden von SchemaSpy angezeigt.
Am besten kombiniert man die Dokumentationserzeugung mit einem Datenbankversionierungstool wie Flyway oder Liquibase. Das Ausrollen von Schemaänderungen triggert dabei die Aktualisierung der Dokumentation. Bei dieser Vorgehensweise kann man zudem auch für ältere Softwarestände das jeweils passende Datenbankschema erzeugen lassen, zusammen mit der entsprechenden DB-Dokumentation für diesen Stand.
Ein wenig Disziplin ist jedoch trotzdem noch gefragt, da die Beschreibungen der DB-Objekte in Form von Kommentaren gepflegt und aktuell gehalten werden wollen.



